From 2b90796be6959d5ef46b38c434a514fce25be971 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 12 Jun 2023 17:45:49 +0200 Subject: [PATCH 001/446] gh-103968: PyType_FromMetaclass: Allow metaclasses with tp_new=NULL (GH-105386) --- Doc/c-api/type.rst | 2 +- Lib/test/test_capi/test_misc.py | 43 ++++++++++++++++--- ...-06-06-14-14-41.gh-issue-103968.BTO6II.rst | 2 + Modules/_testcapi/heaptype.c | 13 ++++++ Objects/typeobject.c | 2 +- 5 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index bf261b9814456e..c99c7ef93a45df 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -258,7 +258,7 @@ The following functions and structs are used to create (or *Py_tp_base[s]* slots if *bases* is ``NULL``, see below). Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not - supported. + supported, except if ``tp_new`` is ``NULL``. (For backwards compatibility, other ``PyType_From*`` functions allow such metaclasses. They ignore ``tp_new``, which may result in incomplete initialization. This is deprecated and in Python 3.14+ such metaclasses will diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 3fcb694198a53a..04a0f8f46cd61e 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -671,31 +671,60 @@ def test_heaptype_with_setattro(self): self.assertEqual(obj.pvalue, 0) def test_heaptype_with_custom_metaclass(self): - self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclass, type)) - self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) + metaclass = _testcapi.HeapCTypeMetaclass + self.assertTrue(issubclass(metaclass, type)) - t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclass) + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) self.assertIsInstance(t, type) self.assertEqual(t.__name__, "HeapCTypeViaMetaclass") - self.assertIs(type(t), _testcapi.HeapCTypeMetaclass) + self.assertIs(type(t), metaclass) + + # Class creation from Python + t = metaclass("PyClassViaMetaclass", (), {}) + self.assertIsInstance(t, type) + self.assertEqual(t.__name__, "PyClassViaMetaclass") + + def test_heaptype_with_custom_metaclass_null_new(self): + metaclass = _testcapi.HeapCTypeMetaclassNullNew + + self.assertTrue(issubclass(metaclass, type)) + + # Class creation from C + t = _testcapi.pytype_fromspec_meta(metaclass) + self.assertIsInstance(t, type) + self.assertEqual(t.__name__, "HeapCTypeViaMetaclass") + self.assertIs(type(t), metaclass) + + # Class creation from Python + with self.assertRaisesRegex(TypeError, "cannot create .* instances"): + metaclass("PyClassViaMetaclass", (), {}) + + def test_heaptype_with_custom_metaclass_custom_new(self): + metaclass = _testcapi.HeapCTypeMetaclassCustomNew + + self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) msg = "Metaclasses with custom tp_new are not supported." with self.assertRaisesRegex(TypeError, msg): - t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew) + t = _testcapi.pytype_fromspec_meta(metaclass) def test_heaptype_with_custom_metaclass_deprecation(self): + metaclass = _testcapi.HeapCTypeMetaclassCustomNew + # gh-103968: a metaclass with custom tp_new is deprecated, but still # allowed for functions that existed in 3.11 # (PyType_FromSpecWithBases is used here). - class Base(metaclass=_testcapi.HeapCTypeMetaclassCustomNew): + class Base(metaclass=metaclass): pass + # Class creation from C with warnings_helper.check_warnings( ('.*custom tp_new.*in Python 3.14.*', DeprecationWarning), ): sub = _testcapi.make_type_with_base(Base) self.assertTrue(issubclass(sub, Base)) - self.assertIsInstance(sub, _testcapi.HeapCTypeMetaclassCustomNew) + self.assertIsInstance(sub, metaclass) def test_multiple_inheritance_ctypes_with_weakref_or_dict(self): diff --git a/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst b/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst new file mode 100644 index 00000000000000..b73103c4e0ad9e --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-06-14-14-41.gh-issue-103968.BTO6II.rst @@ -0,0 +1,2 @@ +:c:func:`PyType_FromMetaclass` now allows metaclasses with ``tp_new`` +set to ``NULL``. diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index 565ab570a42bde..c124871e433431 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -744,6 +744,12 @@ static PyType_Spec HeapCTypeMetaclassCustomNew_spec = { HeapCTypeMetaclassCustomNew_slots }; +static PyType_Spec HeapCTypeMetaclassNullNew_spec = { + .name = "_testcapi.HeapCTypeMetaclassNullNew", + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .slots = empty_type_slots +}; + typedef struct { PyObject_HEAD @@ -1231,6 +1237,13 @@ _PyTestCapi_Init_Heaptype(PyObject *m) { } PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew); + PyObject *HeapCTypeMetaclassNullNew = PyType_FromMetaclass( + &PyType_Type, m, &HeapCTypeMetaclassNullNew_spec, (PyObject *) &PyType_Type); + if (HeapCTypeMetaclassNullNew == NULL) { + return -1; + } + PyModule_AddObject(m, "HeapCTypeMetaclassNullNew", HeapCTypeMetaclassNullNew); + PyObject *HeapCCollection = PyType_FromMetaclass( NULL, m, &HeapCCollection_spec, NULL); if (HeapCCollection == NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0a57991d26251d..1e0d79bc126452 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4236,7 +4236,7 @@ _PyType_FromMetaclass_impl( metaclass); goto finally; } - if (metaclass->tp_new != PyType_Type.tp_new) { + if (metaclass->tp_new && metaclass->tp_new != PyType_Type.tp_new) { if (_allow_tp_new) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, From 4f7d3b602d47d61137e82145f601dccfe6f6cd3c Mon Sep 17 00:00:00 2001 From: Dora203 <66343334+sku2000@users.noreply.github.com> Date: Tue, 13 Jun 2023 00:14:55 +0800 Subject: [PATCH 002/446] gh-105436: The environment block should end with two null wchar_t values (GH-105495) --- Lib/test/test_subprocess.py | 7 +++++++ .../2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst | 2 ++ Modules/_winapi.c | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 51ba423a0f1c92..3d4fffbb8e794a 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1692,6 +1692,13 @@ def test_run_with_pathlike_path_and_arguments(self): res = subprocess.run(args) self.assertEqual(res.returncode, 57) + @unittest.skipUnless(mswindows, "Maybe test trigger a leak on Ubuntu") + def test_run_with_an_empty_env(self): + # gh-105436: fix subprocess.run(..., env={}) broken on Windows + args = [sys.executable, "-c", 'import sys; sys.exit(57)'] + res = subprocess.run(args, env={}) + self.assertEqual(res.returncode, 57) + def test_capture_output(self): cp = self.run_python(("import sys;" "sys.stdout.write('BDFL'); " diff --git a/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst b/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst new file mode 100644 index 00000000000000..1e3f298096cdd6 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-06-08-11-30-17.gh-issue-105436.1qlDxw.rst @@ -0,0 +1,2 @@ +Ensure that an empty environment block is terminated by two null characters, +as is required by Windows. diff --git a/Modules/_winapi.c b/Modules/_winapi.c index af13014bf201b0..a7e6bb582fc64d 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -796,6 +796,17 @@ getenvironment(PyObject* environment) } envsize = PyList_GET_SIZE(keys); + + if (envsize == 0) { + // A environment block must be terminated by two null characters -- + // one for the last string and one for the block. + buffer = PyMem_Calloc(2, sizeof(wchar_t)); + if (!buffer) { + PyErr_NoMemory(); + } + goto cleanup; + } + if (PyList_GET_SIZE(values) != envsize) { PyErr_SetString(PyExc_RuntimeError, "environment changed size during iteration"); @@ -869,7 +880,8 @@ getenvironment(PyObject* environment) *p++ = L'\0'; assert(p == end); - error: +cleanup: +error: Py_XDECREF(keys); Py_XDECREF(values); return buffer; From b9e7dc797d71ce582fdb05be5a0e32d351f24bcb Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 12 Jun 2023 10:47:08 -0700 Subject: [PATCH 003/446] gh-105229: Remove syntactic support for super-instructions (#105703) It will not be used again. --- Tools/cases_generator/generate_cases.py | 143 +++++------------------- Tools/cases_generator/parser.py | 38 ++----- 2 files changed, 38 insertions(+), 143 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 49feb5048e59d8..69216c17ed8780 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -390,7 +390,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"}) offset = 0 context = self.block.context - assert context != None + assert context is not None and context.owner is not None filename = context.owner.filename for line in self.block_text: out.set_lineno(self.block_line + offset, filename) @@ -464,28 +464,14 @@ def write_body(self, out: Formatter, cache_adjust: int) -> None: @dataclasses.dataclass -class SuperOrMacroInstruction: - """Common fields for super- and macro instructions.""" +class MacroInstruction: + """A macro instruction.""" name: str stack: list[StackEffect] initial_sp: int final_sp: int instr_fmt: str - - -@dataclasses.dataclass -class SuperInstruction(SuperOrMacroInstruction): - """A super-instruction.""" - - super: parser.Super - parts: list[Component] - - -@dataclasses.dataclass -class MacroInstruction(SuperOrMacroInstruction): - """A macro instruction.""" - macro: parser.Macro parts: list[Component | parser.CacheEffect] predicted: bool = False @@ -505,7 +491,7 @@ class OverriddenInstructionPlaceHolder: name: str -AnyInstruction = Instruction | SuperInstruction | MacroInstruction +AnyInstruction = Instruction | MacroInstruction INSTR_FMT_PREFIX = "INSTR_FMT_" @@ -538,12 +524,9 @@ def error(self, msg: str, node: parser.Node) -> None: self.errors += 1 everything: list[ - parser.InstDef | parser.Super | parser.Macro | - parser.Pseudo | OverriddenInstructionPlaceHolder + parser.InstDef | parser.Macro | parser.Pseudo | OverriddenInstructionPlaceHolder ] instrs: dict[str, Instruction] # Includes ops - supers: dict[str, parser.Super] - super_instrs: dict[str, SuperInstruction] macros: dict[str, parser.Macro] macro_instrs: dict[str, MacroInstruction] families: dict[str, parser.Family] @@ -558,7 +541,6 @@ def parse(self) -> None: self.everything = [] self.instrs = {} - self.supers = {} self.macros = {} self.families = {} self.pseudos = {} @@ -571,7 +553,7 @@ def parse(self) -> None: files = " + ".join(self.input_filenames) print( f"Read {len(self.instrs)} instructions/ops, " - f"{len(self.supers)} supers, {len(self.macros)} macros, " + f"{len(self.macros)} macros, {len(self.pseudos)} pseudos, " f"and {len(self.families)} families from {files}", file=sys.stderr, ) @@ -605,7 +587,7 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: # Parse from start psr.setpos(start) - thing: parser.InstDef | parser.Super | parser.Macro | parser.Family | None + thing: parser.InstDef | parser.Macro | parser.Family | None thing_first_token = psr.peek() while thing := psr.definition(): match thing: @@ -627,9 +609,6 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: self.instrs[name] = Instruction(thing) instrs_idx[name] = len(self.everything) self.everything.append(thing) - case parser.Super(name): - self.supers[name] = thing - self.everything.append(thing) case parser.Macro(name): self.macros[name] = thing self.everything.append(thing) @@ -648,7 +627,7 @@ def analyze(self) -> None: Raises SystemExit if there is an error. """ - self.analyze_supers_and_macros_and_pseudos() + self.analyze_macros_and_pseudos() self.find_predictions() self.map_families() self.check_families() @@ -656,7 +635,7 @@ def analyze(self) -> None: def find_predictions(self) -> None: """Find the instructions that need PREDICTED() labels.""" for instr in self.instrs.values(): - targets = set() + targets: set[str] = set() for line in instr.block_text: if m := re.match(RE_PREDICTED, line): targets.add(m.group(1)) @@ -760,33 +739,15 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: assert False, f"Unknown instruction {name!r}" return cache, input, output - def analyze_supers_and_macros_and_pseudos(self) -> None: - """Analyze each super-, macro- and pseudo- instruction.""" - self.super_instrs = {} + def analyze_macros_and_pseudos(self) -> None: + """Analyze each super- and macro instruction.""" self.macro_instrs = {} self.pseudo_instrs = {} - for name, super in self.supers.items(): - self.super_instrs[name] = self.analyze_super(super) for name, macro in self.macros.items(): self.macro_instrs[name] = self.analyze_macro(macro) for name, pseudo in self.pseudos.items(): self.pseudo_instrs[name] = self.analyze_pseudo(pseudo) - def analyze_super(self, super: parser.Super) -> SuperInstruction: - components = self.check_super_components(super) - stack, initial_sp = self.stack_analysis(components) - sp = initial_sp - parts: list[Component] = [] - format = "" - for instr in components: - part, sp = self.analyze_instruction(instr, stack, sp) - parts.append(part) - format += instr.instr_fmt - final_sp = sp - return SuperInstruction( - super.name, stack, initial_sp, final_sp, format, super, parts - ) - def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: components = self.check_macro_components(macro) stack, initial_sp = self.stack_analysis(components) @@ -836,15 +797,6 @@ def analyze_instruction( sp += 1 return Component(instr, input_mapping, output_mapping), sp - def check_super_components(self, super: parser.Super) -> list[Instruction]: - components: list[Instruction] = [] - for op in super.ops: - if op.name not in self.instrs: - self.error(f"Unknown instruction {op.name!r}", super) - else: - components.append(self.instrs[op.name]) - return components - def check_macro_components( self, macro: parser.Macro ) -> list[InstructionOrCacheEffect]: @@ -864,7 +816,7 @@ def check_macro_components( def stack_analysis( self, components: typing.Iterable[InstructionOrCacheEffect] ) -> tuple[list[StackEffect], int]: - """Analyze a super-instruction or macro. + """Analyze a macro. Ignore cache effects. @@ -880,8 +832,8 @@ def stack_analysis( # TODO: Eventually this will be needed, at least for macros. self.error( f"Instruction {instr.name!r} has variable-sized stack effect, " - "which are not supported in super- or macro instructions", - instr.inst, # TODO: Pass name+location of super/macro + "which are not supported in macro instructions", + instr.inst, # TODO: Pass name+location of macro ) current -= len(instr.input_effects) lowest = min(lowest, current) @@ -901,7 +853,7 @@ def stack_analysis( return stack, -lowest def get_stack_effect_info( - self, thing: parser.InstDef | parser.Super | parser.Macro | parser.Pseudo + self, thing: parser.InstDef | parser.Macro | parser.Pseudo ) -> tuple[AnyInstruction | None, str, str]: def effect_str(effects: list[StackEffect]) -> str: if getattr(thing, "kind", None) == "legacy": @@ -922,15 +874,6 @@ def effect_str(effects: list[StackEffect]) -> str: instr = None popped = "" pushed = "" - case parser.Super(): - instr = self.super_instrs[thing.name] - # TODO: Same as for Macro below, if needed. - popped = "+".join( - effect_str(comp.instr.input_effects) for comp in instr.parts - ) - pushed = "+".join( - effect_str(comp.instr.output_effects) for comp in instr.parts - ) case parser.Macro(): instr = self.macro_instrs[thing.name] parts = [comp for comp in instr.parts if isinstance(comp, Component)] @@ -1032,8 +975,6 @@ def write_metadata(self) -> None: continue case parser.InstDef(): format = self.instrs[thing.name].instr_fmt - case parser.Super(): - format = self.super_instrs[thing.name].instr_fmt case parser.Macro(): format = self.macro_instrs[thing.name].instr_fmt case parser.Pseudo(): @@ -1092,8 +1033,6 @@ def write_metadata(self) -> None: case parser.InstDef(): if thing.kind != "op": self.write_metadata_for_inst(self.instrs[thing.name]) - case parser.Super(): - self.write_metadata_for_super(self.super_instrs[thing.name]) case parser.Macro(): self.write_metadata_for_macro(self.macro_instrs[thing.name]) case parser.Pseudo(): @@ -1118,12 +1057,6 @@ def write_metadata_for_inst(self, instr: Instruction) -> None: f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," ) - def write_metadata_for_super(self, sup: SuperInstruction) -> None: - """Write metadata for a super-instruction.""" - self.out.emit( - f" [{sup.name}] = {{ true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," - ) - def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" self.out.emit( @@ -1149,7 +1082,6 @@ def write_instructions(self) -> None: # Write and count instructions of all kinds n_instrs = 0 - n_supers = 0 n_macros = 0 n_pseudos = 0 for thing in self.everything: @@ -1160,9 +1092,6 @@ def write_instructions(self) -> None: if thing.kind != "op": n_instrs += 1 self.write_instr(self.instrs[thing.name]) - case parser.Super(): - n_supers += 1 - self.write_super(self.super_instrs[thing.name]) case parser.Macro(): n_macros += 1 self.write_macro(self.macro_instrs[thing.name]) @@ -1172,8 +1101,8 @@ def write_instructions(self) -> None: typing.assert_never(thing) print( - f"Wrote {n_instrs} instructions, {n_supers} supers, {n_macros}" - f" macros and {n_pseudos} pseudos to {self.output_filename}", + f"Wrote {n_instrs} instructions, {n_macros} macros, " + f"and {n_pseudos} pseudos to {self.output_filename}", file=sys.stderr, ) @@ -1197,23 +1126,10 @@ def write_instr(self, instr: Instruction) -> None: self.out.emit("CHECK_EVAL_BREAKER();") self.out.emit(f"DISPATCH();") - def write_super(self, sup: SuperInstruction) -> None: - """Write code for a super-instruction.""" - with self.wrap_super_or_macro(sup): - first = True - for comp in sup.parts: - if not first: - self.out.emit("oparg = (next_instr++)->op.arg;") - # self.out.emit("next_instr += OPSIZE(opcode) - 1;") - first = False - comp.write_body(self.out, 0) - if comp.instr.cache_offset: - self.out.emit(f"next_instr += {comp.instr.cache_offset};") - def write_macro(self, mac: MacroInstruction) -> None: """Write code for a macro instruction.""" last_instr: Instruction | None = None - with self.wrap_super_or_macro(mac): + with self.wrap_macro(mac): cache_adjust = 0 for part in mac.parts: match part: @@ -1239,30 +1155,29 @@ def write_macro(self, mac: MacroInstruction) -> None: ) @contextlib.contextmanager - def wrap_super_or_macro(self, up: SuperOrMacroInstruction): - """Shared boilerplate for super- and macro instructions.""" + def wrap_macro(self, mac: MacroInstruction): + """Boilerplate for macro instructions.""" # TODO: Somewhere (where?) make it so that if one instruction # has an output that is input to another, and the variable names # and types match and don't conflict with other instructions, # that variable is declared with the right name and type in the # outer block, rather than trusting the compiler to optimize it. self.out.emit("") - with self.out.block(f"TARGET({up.name})"): - match up: - case MacroInstruction(predicted=True, name=name): - self.out.emit(f"PREDICTED({name});") - for i, var in reversed(list(enumerate(up.stack))): + with self.out.block(f"TARGET({mac.name})"): + if mac.predicted: + self.out.emit(f"PREDICTED({mac.name});") + for i, var in reversed(list(enumerate(mac.stack))): src = None - if i < up.initial_sp: - src = StackEffect(f"stack_pointer[-{up.initial_sp - i}]", "") + if i < mac.initial_sp: + src = StackEffect(f"stack_pointer[-{mac.initial_sp - i}]", "") self.out.declare(var, src) yield - # TODO: Use slices of up.stack instead of numeric values - self.out.stack_adjust(up.final_sp - up.initial_sp, [], []) + # TODO: Use slices of mac.stack instead of numeric values + self.out.stack_adjust(mac.final_sp - mac.initial_sp, [], []) - for i, var in enumerate(reversed(up.stack[: up.final_sp]), 1): + for i, var in enumerate(reversed(mac.stack[: mac.final_sp]), 1): dst = StackEffect(f"stack_pointer[-{i}]", "") self.out.assign(dst, var) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 56920f23d750c5..2c75989a7e8ab4 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -118,12 +118,6 @@ class InstDef(Node): block: Block -@dataclass -class Super(Node): - name: str - ops: list[OpName] - - @dataclass class Macro(Node): name: str @@ -144,11 +138,9 @@ class Pseudo(Node): class Parser(PLexer): @contextual - def definition(self) -> InstDef | Super | Macro | Family | Pseudo | None: + def definition(self) -> InstDef | Macro | Pseudo | Family | None: if inst := self.inst_def(): return inst - if super := self.super_def(): - return super if macro := self.macro_def(): return macro if family := self.family_def(): @@ -287,25 +279,13 @@ def expression(self) -> Expression | None: return None return Expression(lx.to_text(tokens).strip()) - @contextual - def super_def(self) -> Super | None: - if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "super": - if self.expect(lx.LPAREN): - if tkn := self.expect(lx.IDENTIFIER): - if self.expect(lx.RPAREN): - if self.expect(lx.EQUALS): - if ops := self.ops(): - self.require(lx.SEMI) - res = Super(tkn.text, ops) - return res - - def ops(self) -> list[OpName] | None: - if op := self.op(): - ops = [op] - while self.expect(lx.PLUS): - if op := self.op(): - ops.append(op) - return ops + # def ops(self) -> list[OpName] | None: + # if op := self.op(): + # ops = [op] + # while self.expect(lx.PLUS): + # if op := self.op(): + # ops.append(op) + # return ops @contextual def op(self) -> OpName | None: @@ -432,7 +412,7 @@ def c_blob(self) -> list[lx.Token]: src = sys.argv[2] filename = "" else: - with open(filename) as f: + with open(filename, "r") as f: src = f.read() srclines = src.splitlines() begin = srclines.index("// BEGIN BYTECODES //") From 9544948e7e2f288513137a62308e875dac086a18 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 12 Jun 2023 11:19:04 -0700 Subject: [PATCH 004/446] Remove support for legacy bytecode instructions (#105705) (A legacy instruction is of the form `instr(FOOBAR)`, i.e. missing the `(... -- ...)` stack/cache effect annotation.) --- Tools/cases_generator/generate_cases.py | 4 +--- Tools/cases_generator/parser.py | 7 ++----- Tools/cases_generator/test_generator.py | 14 -------------- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 69216c17ed8780..3a003b3fba2600 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -230,7 +230,7 @@ class Instruction: # Parts of the underlying instruction definition inst: parser.InstDef - kind: typing.Literal["inst", "op", "legacy"] # Legacy means no (input -- output) + kind: typing.Literal["inst", "op"] name: str block: parser.Block block_text: list[str] # Block.text, less curlies, less PREDICT() calls @@ -856,8 +856,6 @@ def get_stack_effect_info( self, thing: parser.InstDef | parser.Macro | parser.Pseudo ) -> tuple[AnyInstruction | None, str, str]: def effect_str(effects: list[StackEffect]) -> str: - if getattr(thing, "kind", None) == "legacy": - return str(-1) n_effect, sym_effect = list_effect_size(effects) if sym_effect: return f"{sym_effect} + {n_effect}" if n_effect else sym_effect diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 2c75989a7e8ab4..ac77e7eae81ad3 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -101,7 +101,7 @@ class OpName(Node): class InstHeader(Node): override: bool register: bool - kind: Literal["inst", "op", "legacy"] # Legacy means no (inputs -- outputs) + kind: Literal["inst", "op"] name: str inputs: list[InputEffect] outputs: list[OutputEffect] @@ -111,7 +111,7 @@ class InstHeader(Node): class InstDef(Node): override: bool register: bool - kind: Literal["inst", "op", "legacy"] + kind: Literal["inst", "op"] name: str inputs: list[InputEffect] outputs: list[OutputEffect] @@ -174,9 +174,6 @@ def inst_header(self) -> InstHeader | None: if self.expect(lx.RPAREN): if (tkn := self.peek()) and tkn.kind == lx.LBRACE: return InstHeader(override, register, kind, name, inp, outp) - elif self.expect(lx.RPAREN) and kind == "inst": - # No legacy stack effect if kind is "op". - return InstHeader(override, register, "legacy", name, [], []) return None def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]: diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index 036094ac8ef487..412d3d14590050 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -62,20 +62,6 @@ def run_cases_test(input: str, expected: str): # print("End") assert actual.rstrip() == expected.rstrip() -def test_legacy(): - input = """ - inst(OP) { - spam(); - } - """ - output = """ - TARGET(OP) { - spam(); - DISPATCH(); - } - """ - run_cases_test(input, output) - def test_inst_no_args(): input = """ inst(OP, (--)) { From f0fb782ddb7208a59cfc38ec4bcbd8d1a81f8a58 Mon Sep 17 00:00:00 2001 From: Jay <74105438+weijay0804@users.noreply.github.com> Date: Tue, 13 Jun 2023 04:29:02 +0800 Subject: [PATCH 005/446] gh-105331: Change `asyncio.sleep` to raise ``ValueError` for nan (#105641) Co-authored-by: Guido van Rossum Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Doc/library/asyncio-task.rst | 3 +++ Lib/asyncio/tasks.py | 4 ++++ Lib/test/test_asyncio/test_tasks.py | 15 +++++++++++++++ ...2023-06-11-09-14-30.gh-issue-105331.nlZvoW.rst | 2 ++ 4 files changed, 24 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-11-09-14-30.gh-issue-105331.nlZvoW.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index fe8d028150403d..3618bcb6d7c6b5 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -426,6 +426,9 @@ Sleeping .. versionchanged:: 3.10 Removed the *loop* parameter. + .. versionchanged:: 3.13 + Raises :exc:`ValueError` if *delay* is :data:`~math.nan`. + Running Tasks Concurrently ========================== diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 8d5bde09ea9b5b..4250bb0753879a 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -15,6 +15,7 @@ import functools import inspect import itertools +import math import types import warnings import weakref @@ -646,6 +647,9 @@ async def sleep(delay, result=None): await __sleep0() return result + if math.isnan(delay): + raise ValueError("Invalid delay: NaN (not a number)") + loop = events.get_running_loop() future = loop.create_future() h = loop.call_later(delay, diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 6e8a51ce2555d5..4dfaff847edb90 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1609,6 +1609,21 @@ async def sleeper(dt, arg): self.assertEqual(t.result(), 'yeah') self.assertAlmostEqual(0.1, loop.time()) + def test_sleep_when_delay_is_nan(self): + + def gen(): + yield + + loop = self.new_test_loop(gen) + + async def sleeper(): + await asyncio.sleep(float("nan")) + + t = self.new_task(loop, sleeper()) + + with self.assertRaises(ValueError): + loop.run_until_complete(t) + def test_sleep_cancel(self): def gen(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-11-09-14-30.gh-issue-105331.nlZvoW.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-11-09-14-30.gh-issue-105331.nlZvoW.rst new file mode 100644 index 00000000000000..4a3fee0dd64ae0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-11-09-14-30.gh-issue-105331.nlZvoW.rst @@ -0,0 +1,2 @@ +Raise :exc:`ValueError` if the ``delay`` argument to :func:`asyncio.sleep` is a NaN (matching :func:`time.sleep`). + From ca3cc4b95d66f7527ebe0ba4cdb1907082d9bfc8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 12 Jun 2023 23:35:07 +0200 Subject: [PATCH 006/446] gh-105375: Explicitly initialise all {Pickler,Unpickler}Object fields (#105686) All fields must be explicitly initialised to prevent manipulation of uninitialised fields in dealloc. Align initialisation order with the layout of the object structs. --- Modules/_pickle.c | 90 ++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/Modules/_pickle.c b/Modules/_pickle.c index e6eb9c741e1adc..9e70fee84e18d3 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1145,42 +1145,49 @@ _Pickler_Write(PicklerObject *self, const char *s, Py_ssize_t data_len) static PicklerObject * _Pickler_New(PickleState *st) { - PicklerObject *self; - - self = PyObject_GC_New(PicklerObject, st->Pickler_Type); - if (self == NULL) + PyMemoTable *memo = PyMemoTable_New(); + if (memo == NULL) { return NULL; + } + + const Py_ssize_t max_output_len = WRITE_BUF_SIZE; + PyObject *output_buffer = PyBytes_FromStringAndSize(NULL, max_output_len); + if (output_buffer == NULL) { + goto error; + } + PicklerObject *self = PyObject_GC_New(PicklerObject, st->Pickler_Type); + if (self == NULL) { + goto error; + } + + self->memo = memo; self->pers_func = NULL; + self->pers_func_self = NULL; self->dispatch_table = NULL; - self->buffer_callback = NULL; + self->reducer_override = NULL; self->write = NULL; + self->output_buffer = output_buffer; + self->output_len = 0; + self->max_output_len = max_output_len; self->proto = 0; self->bin = 0; self->framing = 0; self->frame_start = -1; + self->buf_size = 0; self->fast = 0; self->fast_nesting = 0; self->fix_imports = 0; self->fast_memo = NULL; - self->max_output_len = WRITE_BUF_SIZE; - self->output_len = 0; - self->reducer_override = NULL; - - self->memo = PyMemoTable_New(); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } - self->output_buffer = PyBytes_FromStringAndSize(NULL, - self->max_output_len); - if (self->output_buffer == NULL) { - Py_DECREF(self); - return NULL; - } + self->buffer_callback = NULL; PyObject_GC_Track(self); return self; + +error: + PyMem_Free(memo); + Py_XDECREF(output_buffer); + return NULL; } static int @@ -1628,14 +1635,31 @@ _Unpickler_MemoCleanup(UnpicklerObject *self) static UnpicklerObject * _Unpickler_New(PyObject *module) { - UnpicklerObject *self; + const int MEMO_SIZE = 32; + PyObject **memo = _Unpickler_NewMemo(MEMO_SIZE); + if (memo == NULL) { + return NULL; + } + PickleState *st = _Pickle_GetState(module); + PyObject *stack = Pdata_New(st); + if (stack == NULL) { + goto error; + } - self = PyObject_GC_New(UnpicklerObject, st->Unpickler_Type); - if (self == NULL) - return NULL; + UnpicklerObject *self = PyObject_GC_New(UnpicklerObject, + st->Unpickler_Type); + if (self == NULL) { + goto error; + } + self->stack = (Pdata *)stack; + self->memo = memo; + self->memo_size = MEMO_SIZE; + self->memo_len = 0; self->pers_func = NULL; + self->pers_func_self = NULL; + memset(&self->buffer, 0, sizeof(Py_buffer)); self->input_buffer = NULL; self->input_line = NULL; self->input_len = 0; @@ -1653,22 +1677,14 @@ _Unpickler_New(PyObject *module) self->marks_size = 0; self->proto = 0; self->fix_imports = 0; - memset(&self->buffer, 0, sizeof(Py_buffer)); - self->memo_size = 32; - self->memo_len = 0; - self->memo = _Unpickler_NewMemo(self->memo_size); - if (self->memo == NULL) { - Py_DECREF(self); - return NULL; - } - self->stack = (Pdata *)Pdata_New(st); - if (self->stack == NULL) { - Py_DECREF(self); - return NULL; - } PyObject_GC_Track(self); return self; + +error: + PyMem_Free(memo); + Py_XDECREF(stack); + return NULL; } /* Returns -1 (with an exception set) on failure, 0 on success. This may From 8da9d1b16319f4a6bd78435016ef1f4bef6e2b41 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 12 Jun 2023 14:55:15 -0700 Subject: [PATCH 007/446] gh-105540: Fix code generator tests (#105707) This involves expanding PEEK, POKE and JUMPBY macros, and removing super and register tests (those features no longer exist). --- Tools/cases_generator/test_generator.py | 175 +++++++----------------- 1 file changed, 47 insertions(+), 128 deletions(-) diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index 412d3d14590050..f8c79976fb722e 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -43,7 +43,8 @@ def run_cases_test(input: str, expected: str): temp_input.write(generate_cases.END_MARKER) temp_input.flush() temp_output = tempfile.NamedTemporaryFile("w+") - a = generate_cases.Analyzer(temp_input.name, temp_output.name) + temp_metadata = tempfile.NamedTemporaryFile("w+") + a = generate_cases.Analyzer([temp_input.name], temp_output.name, temp_metadata.name) a.parse() a.analyze() if a.errors: @@ -84,7 +85,7 @@ def test_inst_one_pop(): """ output = """ TARGET(OP) { - PyObject *value = PEEK(1); + PyObject *value = stack_pointer[-1]; spam(); STACK_SHRINK(1); DISPATCH(); @@ -103,7 +104,7 @@ def test_inst_one_push(): PyObject *res; spam(); STACK_GROW(1); - POKE(1, res); + stack_pointer[-1] = res; DISPATCH(); } """ @@ -117,10 +118,10 @@ def test_inst_one_push_one_pop(): """ output = """ TARGET(OP) { - PyObject *value = PEEK(1); + PyObject *value = stack_pointer[-1]; PyObject *res; spam(); - POKE(1, res); + stack_pointer[-1] = res; DISPATCH(); } """ @@ -134,12 +135,12 @@ def test_binary_op(): """ output = """ TARGET(OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; PyObject *res; spam(); STACK_SHRINK(1); - POKE(1, res); + stack_pointer[-1] = res; DISPATCH(); } """ @@ -153,11 +154,11 @@ def test_overlap(): """ output = """ TARGET(OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; PyObject *result; spam(); - POKE(1, result); + stack_pointer[-1] = result; DISPATCH(); } """ @@ -167,11 +168,8 @@ def test_predictions_and_eval_breaker(): input = """ inst(OP1, (--)) { } - inst(OP2, (--)) { - } inst(OP3, (arg -- res)) { DEOPT_IF(xxx, OP1); - PREDICT(OP2); CHECK_EVAL_BREAKER(); } """ @@ -181,17 +179,11 @@ def test_predictions_and_eval_breaker(): DISPATCH(); } - TARGET(OP2) { - PREDICTED(OP2); - DISPATCH(); - } - TARGET(OP3) { - PyObject *arg = PEEK(1); + PyObject *arg = stack_pointer[-1]; PyObject *res; DEOPT_IF(xxx, OP1); - POKE(1, res); - PREDICT(OP2); + stack_pointer[-1] = res; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -234,12 +226,12 @@ def test_error_if_pop(): """ output = """ TARGET(OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; PyObject *res; if (cond) goto pop_2_label; STACK_SHRINK(1); - POKE(1, res); + stack_pointer[-1] = res; DISPATCH(); } """ @@ -252,11 +244,11 @@ def test_cache_effect(): """ output = """ TARGET(OP) { - PyObject *value = PEEK(1); + PyObject *value = stack_pointer[-1]; uint16_t counter = read_u16(&next_instr[0].cache); uint32_t extra = read_u32(&next_instr[1].cache); STACK_SHRINK(1); - JUMPBY(3); + next_instr += 3; DISPATCH(); } """ @@ -275,59 +267,6 @@ def test_suppress_dispatch(): """ run_cases_test(input, output) -def test_super_instruction(): - # TODO: Test cache effect - input = """ - inst(OP1, (counter/1, arg --)) { - op1(); - } - inst(OP2, (extra/2, arg --)) { - op2(); - } - super(OP) = OP1 + OP2; - """ - output = """ - TARGET(OP1) { - PyObject *arg = PEEK(1); - uint16_t counter = read_u16(&next_instr[0].cache); - op1(); - STACK_SHRINK(1); - JUMPBY(1); - DISPATCH(); - } - - TARGET(OP2) { - PyObject *arg = PEEK(1); - uint32_t extra = read_u32(&next_instr[0].cache); - op2(); - STACK_SHRINK(1); - JUMPBY(2); - DISPATCH(); - } - - TARGET(OP) { - PyObject *_tmp_1 = PEEK(1); - PyObject *_tmp_2 = PEEK(2); - { - PyObject *arg = _tmp_1; - uint16_t counter = read_u16(&next_instr[0].cache); - op1(); - } - JUMPBY(1); - NEXTOPARG(); - JUMPBY(1); - { - PyObject *arg = _tmp_2; - uint32_t extra = read_u32(&next_instr[0].cache); - op2(); - } - JUMPBY(2); - STACK_SHRINK(2); - DISPATCH(); - } - """ - run_cases_test(input, output) - def test_macro_instruction(): input = """ inst(OP1, (counter/1, left, right -- left, right)) { @@ -344,18 +283,18 @@ def test_macro_instruction(): """ output = """ TARGET(OP1) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); op1(left, right); - JUMPBY(1); + next_instr += 1; DISPATCH(); } TARGET(OP) { - PyObject *_tmp_1 = PEEK(1); - PyObject *_tmp_2 = PEEK(2); - PyObject *_tmp_3 = PEEK(3); + PyObject *_tmp_1 = stack_pointer[-1]; + PyObject *_tmp_2 = stack_pointer[-2]; + PyObject *_tmp_3 = stack_pointer[-3]; { PyObject *right = _tmp_1; PyObject *left = _tmp_2; @@ -373,22 +312,22 @@ def test_macro_instruction(): res = op2(arg2, left, right); _tmp_3 = res; } - JUMPBY(5); + next_instr += 5; static_assert(INLINE_CACHE_ENTRIES_OP == 5, "incorrect cache size"); STACK_SHRINK(2); - POKE(1, _tmp_3); + stack_pointer[-1] = _tmp_3; DISPATCH(); } TARGET(OP3) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *arg2 = PEEK(3); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *arg2 = stack_pointer[-3]; PyObject *res; res = op3(arg2, left, right); STACK_SHRINK(2); - POKE(1, res); - JUMPBY(5); + stack_pointer[-1] = res; + next_instr += 5; DISPATCH(); } """ @@ -402,9 +341,9 @@ def test_array_input(): """ output = """ TARGET(OP) { - PyObject *above = PEEK(1); - PyObject **values = &PEEK(1 + oparg*2); - PyObject *below = PEEK(2 + oparg*2); + PyObject *above = stack_pointer[-1]; + PyObject **values = (stack_pointer - (1 + oparg*2)); + PyObject *below = stack_pointer[-(2 + oparg*2)]; spam(); STACK_SHRINK(oparg*2); STACK_SHRINK(2); @@ -426,8 +365,8 @@ def test_array_output(): PyObject *above; spam(values, oparg); STACK_GROW(oparg*3); - POKE(1, above); - POKE(2 + oparg*3, below); + stack_pointer[-1] = above; + stack_pointer[-(2 + oparg*3)] = below; DISPATCH(); } """ @@ -441,11 +380,11 @@ def test_array_input_output(): """ output = """ TARGET(OP) { - PyObject **values = &PEEK(oparg); + PyObject **values = (stack_pointer - oparg); PyObject *above; spam(values, oparg); STACK_GROW(1); - POKE(1, above); + stack_pointer[-1] = above; DISPATCH(); } """ @@ -459,8 +398,8 @@ def test_array_error_if(): """ output = """ TARGET(OP) { - PyObject **values = &PEEK(oparg); - PyObject *extra = PEEK(1 + oparg); + PyObject **values = (stack_pointer - oparg); + PyObject *extra = stack_pointer[-(1 + oparg)]; if (oparg == 0) { STACK_SHRINK(oparg); goto pop_1_somewhere; } STACK_SHRINK(oparg); STACK_SHRINK(1); @@ -469,26 +408,6 @@ def test_array_error_if(): """ run_cases_test(input, output) -def test_register(): - input = """ - register inst(OP, (counter/1, left, right -- result)) { - result = op(left, right); - } - """ - output = """ - TARGET(OP) { - PyObject *left = REG(oparg1); - PyObject *right = REG(oparg2); - PyObject *result; - uint16_t counter = read_u16(&next_instr[0].cache); - result = op(left, right); - Py_XSETREF(REG(oparg3), result); - JUMPBY(1); - DISPATCH(); - } - """ - run_cases_test(input, output) - def test_cond_effect(): input = """ inst(OP, (aa, input if ((oparg & 1) == 1), cc -- xx, output if (oparg & 2), zz)) { @@ -497,18 +416,18 @@ def test_cond_effect(): """ output = """ TARGET(OP) { - PyObject *cc = PEEK(1); - PyObject *input = ((oparg & 1) == 1) ? PEEK(1 + (((oparg & 1) == 1) ? 1 : 0)) : NULL; - PyObject *aa = PEEK(2 + (((oparg & 1) == 1) ? 1 : 0)); + PyObject *cc = stack_pointer[-1]; + PyObject *input = ((oparg & 1) == 1) ? stack_pointer[-(1 + (((oparg & 1) == 1) ? 1 : 0))] : NULL; + PyObject *aa = stack_pointer[-(2 + (((oparg & 1) == 1) ? 1 : 0))]; PyObject *xx; PyObject *output = NULL; PyObject *zz; output = spam(oparg, input); STACK_SHRINK((((oparg & 1) == 1) ? 1 : 0)); STACK_GROW(((oparg & 2) ? 1 : 0)); - POKE(1, zz); - if (oparg & 2) { POKE(1 + ((oparg & 2) ? 1 : 0), output); } - POKE(2 + ((oparg & 2) ? 1 : 0), xx); + stack_pointer[-1] = zz; + if (oparg & 2) { stack_pointer[-(1 + ((oparg & 2) ? 1 : 0))] = output; } + stack_pointer[-(2 + ((oparg & 2) ? 1 : 0))] = xx; DISPATCH(); } """ From 829ac13b69a2b53153e1b40670e6ef82f05130c1 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:11:34 +0530 Subject: [PATCH 008/446] GH-104787: use bitfields in `_asyncio` (#104788) --- Modules/_asynciomodule.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 08ce172c6a8fcb..4b84c1de66be0e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -119,11 +119,14 @@ typedef enum { PyObject *prefix##_result; \ PyObject *prefix##_source_tb; \ PyObject *prefix##_cancel_msg; \ - fut_state prefix##_state; \ - int prefix##_log_tb; \ - int prefix##_blocking; \ PyObject *prefix##_weakreflist; \ - PyObject *prefix##_cancelled_exc; + PyObject *prefix##_cancelled_exc; \ + fut_state prefix##_state; \ + /* These bitfields need to be at the end of the struct + so that these and bitfields from TaskObj are contiguous. + */ \ + unsigned prefix##_log_tb: 1; \ + unsigned prefix##_blocking: 1; typedef struct { FutureObj_HEAD(fut) @@ -131,13 +134,13 @@ typedef struct { typedef struct { FutureObj_HEAD(task) + unsigned task_must_cancel: 1; + unsigned task_log_destroy_pending: 1; + int task_num_cancels_requested; PyObject *task_fut_waiter; PyObject *task_coro; PyObject *task_name; PyObject *task_context; - int task_must_cancel; - int task_log_destroy_pending; - int task_num_cancels_requested; } TaskObj; typedef struct { From 840d02f3f0cd341207db6d918ce7f0987be9952e Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:36:40 +0530 Subject: [PATCH 009/446] GH-105684: Require `asyncio.Task` implementations to support `set_name` method (#105685) --- Lib/asyncio/base_events.py | 2 +- Lib/asyncio/taskgroups.py | 2 +- Lib/asyncio/tasks.py | 15 +-------------- Lib/test/test_asyncio/test_runners.py | 2 ++ ...2023-06-12-10-40-38.gh-issue-105684.yiHkFD.rst | 3 +++ 5 files changed, 8 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-12-10-40-38.gh-issue-105684.yiHkFD.rst diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 32d7e1c481ecc5..f650e6b0488cf8 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -443,7 +443,7 @@ def create_task(self, coro, *, name=None, context=None): else: task = self._task_factory(self, coro, context=context) - tasks._set_task_name(task, name) + task.set_name(name) return task diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 06b2e0db86a1fe..bf92bbaf0d0058 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -163,7 +163,7 @@ def create_task(self, coro, *, name=None, context=None): task = self._loop.create_task(coro) else: task = self._loop.create_task(coro, context=context) - tasks._set_task_name(task, name) + task.set_name(name) # optimization: Immediately call the done callback if the task is # already done (e.g. if the coro was able to complete eagerly), # and skip scheduling a done callback diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 4250bb0753879a..75dd3cb6c2e987 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -68,19 +68,6 @@ def all_tasks(loop=None): if futures._get_loop(t) is loop and not t.done()} -def _set_task_name(task, name): - if name is not None: - try: - set_name = task.set_name - except AttributeError: - warnings.warn("Task.set_name() was added in Python 3.8, " - "the method support will be mandatory for third-party " - "task implementations since 3.13.", - DeprecationWarning, stacklevel=3) - else: - set_name(name) - - class Task(futures._PyFuture): # Inherit Python Task implementation # from a Python Future implementation. @@ -412,7 +399,7 @@ def create_task(coro, *, name=None, context=None): else: task = loop.create_task(coro, context=context) - _set_task_name(task, name) + task.set_name(name) return task diff --git a/Lib/test/test_asyncio/test_runners.py b/Lib/test/test_asyncio/test_runners.py index 811cf8b72488b8..b1eb6f492886b3 100644 --- a/Lib/test/test_asyncio/test_runners.py +++ b/Lib/test/test_asyncio/test_runners.py @@ -243,6 +243,8 @@ def exception(self, *args, **kwargs): def get_loop(self, *args, **kwargs): return self._task.get_loop(*args, **kwargs) + def set_name(self, *args, **kwargs): + return self._task.set_name(*args, **kwargs) async def main(): interrupt_self() diff --git a/Misc/NEWS.d/next/Library/2023-06-12-10-40-38.gh-issue-105684.yiHkFD.rst b/Misc/NEWS.d/next/Library/2023-06-12-10-40-38.gh-issue-105684.yiHkFD.rst new file mode 100644 index 00000000000000..b0d4eb328a7b34 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-12-10-40-38.gh-issue-105684.yiHkFD.rst @@ -0,0 +1,3 @@ +Supporting :meth:`asyncio.Task.set_name` is now mandatory for third party task implementations. +The undocumented :func:`!_set_task_name` function (deprecated since 3.8) has been removed. +Patch by Kumar Aditya. From 217589d4f3246d67c6ef0eb0be2b1c33987cf260 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 13 Jun 2023 10:38:01 +0200 Subject: [PATCH 010/446] gh-105375: Improve error handling in _Unpickler_SetInputStream() (#105667) Prevent exceptions from possibly being overwritten in case of multiple failures. --- ...-06-11-22-46-06.gh-issue-105375.YkhSNt.rst | 2 ++ Modules/_pickle.c | 31 +++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst diff --git a/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst b/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst new file mode 100644 index 00000000000000..dda8f428760ba1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-11-22-46-06.gh-issue-105375.YkhSNt.rst @@ -0,0 +1,2 @@ +Fix a bug in :c:func:`!_Unpickler_SetInputStream` where an exception could +end up being overwritten in case of failure. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 9e70fee84e18d3..4913a8dfee589e 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1694,25 +1694,30 @@ _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file) { /* Optional file methods */ if (_PyObject_LookupAttr(file, &_Py_ID(peek), &self->peek) < 0) { - return -1; + goto error; } if (_PyObject_LookupAttr(file, &_Py_ID(readinto), &self->readinto) < 0) { - return -1; + goto error; + } + if (_PyObject_LookupAttr(file, &_Py_ID(read), &self->read) < 0) { + goto error; + } + if (_PyObject_LookupAttr(file, &_Py_ID(readline), &self->readline) < 0) { + goto error; } - (void)_PyObject_LookupAttr(file, &_Py_ID(read), &self->read); - (void)_PyObject_LookupAttr(file, &_Py_ID(readline), &self->readline); if (!self->readline || !self->read) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "file must have 'read' and 'readline' attributes"); - } - Py_CLEAR(self->read); - Py_CLEAR(self->readinto); - Py_CLEAR(self->readline); - Py_CLEAR(self->peek); - return -1; + PyErr_SetString(PyExc_TypeError, + "file must have 'read' and 'readline' attributes"); + goto error; } return 0; + +error: + Py_CLEAR(self->read); + Py_CLEAR(self->readinto); + Py_CLEAR(self->readline); + Py_CLEAR(self->peek); + return -1; } /* Returns -1 (with an exception set) on failure, 0 on success. This may From 09ffa69e2e84950751739ab500f820725e00a3dd Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 13 Jun 2023 09:51:05 +0100 Subject: [PATCH 011/446] GH-105678: Split MAKE_FUNCTION into MAKE_FUNCTION and SET_FUNCTION_ATTRIBUTE (GH-105680) --- Include/internal/pycore_opcode.h | 32 +- Include/opcode.h | 85 +-- Lib/dis.py | 8 +- Lib/importlib/_bootstrap_external.py | 4 +- Lib/opcode.py | 3 +- Lib/test/test_dis.py | 64 +- ...-06-07-21-27-55.gh-issue-105678.wKOr7F.rst | 4 + Python/bytecodes.c | 55 +- Python/compile.c | 16 +- Python/generated_cases.c.h | 600 +++++++++--------- Python/opcode_metadata.h | 9 +- Python/opcode_targets.h | 30 +- 12 files changed, 480 insertions(+), 430 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-07-21-27-55.gh-issue-105678.wKOr7F.rst diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 450ae8f5da7b29..d706b85b6e43f7 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -214,6 +214,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [SEND_GEN] = SEND, [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, [SET_ADD] = SET_ADD, + [SET_FUNCTION_ATTRIBUTE] = SET_FUNCTION_ATTRIBUTE, [SET_UPDATE] = SET_UPDATE, [STORE_ATTR] = STORE_ATTR, [STORE_ATTR_INSTANCE_VALUE] = STORE_ATTR, @@ -269,20 +270,21 @@ static const char *const _PyOpcode_OpName[267] = { [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [MAKE_FUNCTION] = "MAKE_FUNCTION", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", @@ -293,7 +295,6 @@ static const char *const _PyOpcode_OpName[267] = { [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -301,39 +302,39 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [COMPARE_OP_INT] = "COMPARE_OP_INT", - [COMPARE_OP_STR] = "COMPARE_OP_STR", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", - [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_LOCALS] = "LOAD_LOCALS", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -356,9 +357,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -377,7 +378,7 @@ static const char *const _PyOpcode_OpName[267] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [MAKE_FUNCTION] = "MAKE_FUNCTION", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", @@ -422,7 +423,7 @@ static const char *const _PyOpcode_OpName[267] = { [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS", [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF", - [177] = "<177>", + [SET_FUNCTION_ATTRIBUTE] = "SET_FUNCTION_ATTRIBUTE", [178] = "<178>", [179] = "<179>", [180] = "<180>", @@ -520,7 +521,6 @@ static const char *const _PyOpcode_OpName[267] = { case 161: \ case 166: \ case 167: \ - case 177: \ case 178: \ case 179: \ case 180: \ diff --git a/Include/opcode.h b/Include/opcode.h index 7f69fd6d322bd8..be538999d1496f 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -19,6 +19,7 @@ extern "C" { #define UNARY_NOT 12 #define UNARY_INVERT 15 #define RESERVED 17 +#define MAKE_FUNCTION 24 #define BINARY_SUBSCR 25 #define BINARY_SLICE 26 #define STORE_SLICE 27 @@ -87,7 +88,6 @@ extern "C" { #define POP_JUMP_IF_NONE 129 #define RAISE_VARARGS 130 #define GET_AWAITABLE 131 -#define MAKE_FUNCTION 132 #define BUILD_SLICE 133 #define JUMP_BACKWARD_NO_INTERRUPT 134 #define MAKE_CELL 135 @@ -123,6 +123,7 @@ extern "C" { #define CALL_INTRINSIC_2 174 #define LOAD_FROM_DICT_OR_GLOBALS 175 #define LOAD_FROM_DICT_OR_DEREF 176 +#define SET_FUNCTION_ATTRIBUTE 177 #define ENTER_EXECUTOR 230 #define MIN_INSTRUMENTED_OPCODE 237 #define INSTRUMENTED_LOAD_SUPER_ATTR 237 @@ -169,47 +170,47 @@ extern "C" { #define BINARY_SUBSCR_LIST_INT 21 #define BINARY_SUBSCR_TUPLE_INT 22 #define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 24 -#define CALL_BOUND_METHOD_EXACT_ARGS 28 -#define CALL_BUILTIN_CLASS 29 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 -#define CALL_NO_KW_BUILTIN_FAST 39 -#define CALL_NO_KW_BUILTIN_O 40 -#define CALL_NO_KW_ISINSTANCE 41 -#define CALL_NO_KW_LEN 42 -#define CALL_NO_KW_LIST_APPEND 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 -#define CALL_NO_KW_STR_1 47 -#define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 56 -#define COMPARE_OP_FLOAT 57 -#define COMPARE_OP_INT 58 -#define COMPARE_OP_STR 59 -#define FOR_ITER_LIST 62 -#define FOR_ITER_TUPLE 63 -#define FOR_ITER_RANGE 64 -#define FOR_ITER_GEN 65 -#define LOAD_SUPER_ATTR_ATTR 66 -#define LOAD_SUPER_ATTR_METHOD 67 -#define LOAD_ATTR_CLASS 70 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 72 -#define LOAD_ATTR_INSTANCE_VALUE 73 -#define LOAD_ATTR_MODULE 76 -#define LOAD_ATTR_PROPERTY 77 -#define LOAD_ATTR_SLOT 78 -#define LOAD_ATTR_WITH_HINT 79 -#define LOAD_ATTR_METHOD_LAZY_DICT 80 -#define LOAD_ATTR_METHOD_NO_DICT 81 -#define LOAD_ATTR_METHOD_WITH_VALUES 82 -#define LOAD_GLOBAL_BUILTIN 84 -#define LOAD_GLOBAL_MODULE 86 -#define STORE_ATTR_INSTANCE_VALUE 88 -#define STORE_ATTR_SLOT 111 -#define STORE_ATTR_WITH_HINT 112 -#define STORE_SUBSCR_DICT 113 +#define CALL_PY_WITH_DEFAULTS 28 +#define CALL_BOUND_METHOD_EXACT_ARGS 29 +#define CALL_BUILTIN_CLASS 34 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 38 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 39 +#define CALL_NO_KW_BUILTIN_FAST 40 +#define CALL_NO_KW_BUILTIN_O 41 +#define CALL_NO_KW_ISINSTANCE 42 +#define CALL_NO_KW_LEN 43 +#define CALL_NO_KW_LIST_APPEND 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 46 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 47 +#define CALL_NO_KW_STR_1 48 +#define CALL_NO_KW_TUPLE_1 56 +#define CALL_NO_KW_TYPE_1 57 +#define COMPARE_OP_FLOAT 58 +#define COMPARE_OP_INT 59 +#define COMPARE_OP_STR 62 +#define FOR_ITER_LIST 63 +#define FOR_ITER_TUPLE 64 +#define FOR_ITER_RANGE 65 +#define FOR_ITER_GEN 66 +#define LOAD_SUPER_ATTR_ATTR 67 +#define LOAD_SUPER_ATTR_METHOD 70 +#define LOAD_ATTR_CLASS 72 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 82 +#define LOAD_ATTR_METHOD_WITH_VALUES 84 +#define LOAD_GLOBAL_BUILTIN 86 +#define LOAD_GLOBAL_MODULE 88 +#define STORE_ATTR_INSTANCE_VALUE 111 +#define STORE_ATTR_SLOT 112 +#define STORE_ATTR_WITH_HINT 113 +#define STORE_SUBSCR_DICT 132 #define STORE_SUBSCR_LIST_INT 148 #define UNPACK_SEQUENCE_LIST 153 #define UNPACK_SEQUENCE_TUPLE 154 diff --git a/Lib/dis.py b/Lib/dis.py index 596deede2013e5..dd5ad41dc3295f 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -32,8 +32,8 @@ (repr, 'repr'), (ascii, 'ascii'), ) -MAKE_FUNCTION = opmap['MAKE_FUNCTION'] -MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') +SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE'] +FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') LOAD_CONST = opmap['LOAD_CONST'] RETURN_CONST = opmap['RETURN_CONST'] @@ -586,8 +586,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None, if argrepr: argrepr += ', ' argrepr += 'with format' - elif deop == MAKE_FUNCTION: - argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS) + elif deop == SET_FUNCTION_ATTRIBUTE: + argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS) if arg & (1< at 0x..., file "%s", line %d>) - MAKE_FUNCTION 0 + MAKE_FUNCTION LOAD_FAST 0 (x) GET_ITER CALL 0 @@ -686,7 +686,8 @@ def foo(x): %3d LOAD_CLOSURE 0 (y) BUILD_TUPLE 1 LOAD_CONST 1 () - MAKE_FUNCTION 8 (closure) + MAKE_FUNCTION + SET_FUNCTION_ATTRIBUTE 8 (closure) STORE_FAST 1 (foo) %3d LOAD_FAST 1 (foo) @@ -709,7 +710,8 @@ def foo(x): LOAD_CLOSURE 0 (x) BUILD_TUPLE 1 LOAD_CONST 1 ( at 0x..., file "%s", line %d>) - MAKE_FUNCTION 8 (closure) + MAKE_FUNCTION + SET_FUNCTION_ATTRIBUTE 8 (closure) LOAD_DEREF 1 (y) GET_ITER CALL 0 @@ -1566,7 +1568,7 @@ def jumpy(): def _stringify_instruction(instr): # Since line numbers and other offsets change a lot for these # test cases, ignore them. - return str(instr._replace(positions=None)) + return repr(instr._replace(positions=None)) def _prepare_test_cases(): _instructions = dis.get_instructions(outer, first_line=expected_outer_line) @@ -1596,20 +1598,22 @@ def _prepare_test_cases(): Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=20, start_offset=20, starts_line=7, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=30, start_offset=30, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=32, start_offset=32, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='', argrepr="''", offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=1, argrepr='1', offset=36, start_offset=36, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=38, start_offset=38, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, start_offset=52, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=54, start_offset=54, starts_line=8, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=24, start_offset=24, starts_line=7, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=1, argrepr='1', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, start_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, start_offset=58, starts_line=8, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_f = [ @@ -1624,17 +1628,19 @@ def _prepare_test_cases(): Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=26, start_offset=26, starts_line=5, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=36, start_offset=36, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=38, start_offset=38, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, start_offset=52, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=54, start_offset=54, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=177, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=28, start_offset=28, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=30, start_offset=30, starts_line=5, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=40, start_offset=40, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=42, start_offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=44, start_offset=44, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=46, start_offset=46, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=48, start_offset=48, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, start_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, start_offset=58, starts_line=6, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_inner = [ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-07-21-27-55.gh-issue-105678.wKOr7F.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-07-21-27-55.gh-issue-105678.wKOr7F.rst new file mode 100644 index 00000000000000..fd38c14c140414 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-07-21-27-55.gh-issue-105678.wKOr7F.rst @@ -0,0 +1,4 @@ +Break the ``MAKE_FUNCTION`` instruction into two parts, ``MAKE_FUNCTION`` +which makes the function and ``SET_FUNCTION_ATTRIBUTE`` which sets the +attributes on the function. This makes the stack effect of ``MAKE_FUNCTION`` +regular to ease optimization and code generation. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f0b2dc7976c6fc..cd8b674370b7eb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -83,15 +83,14 @@ dummy_func( // Dummy labels. pop_1_error: // Dummy locals. - PyObject *annotations; + PyObject *dummy; + PyObject *attr; PyObject *attrs; PyObject *bottom; PyObject *callable; PyObject *callargs; - PyObject *closure; PyObject *codeobj; PyObject *cond; - PyObject *defaults; PyObject *descr; _PyInterpreterFrame entry_frame; PyObject *exc; @@ -3297,11 +3296,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(MAKE_FUNCTION, (defaults if (oparg & MAKE_FUNCTION_DEFAULTS), - kwdefaults if (oparg & MAKE_FUNCTION_KWDEFAULTS), - annotations if (oparg & MAKE_FUNCTION_ANNOTATIONS), - closure if (oparg & MAKE_FUNCTION_CLOSURE), - codeobj -- func)) { + inst(MAKE_FUNCTION, (codeobj -- func)) { PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -3311,27 +3306,37 @@ dummy_func( goto error; } - if (oparg & MAKE_FUNCTION_CLOSURE) { - assert(PyTuple_CheckExact(closure)); - func_obj->func_closure = closure; - } - if (oparg & MAKE_FUNCTION_ANNOTATIONS) { - assert(PyTuple_CheckExact(annotations)); - func_obj->func_annotations = annotations; - } - if (oparg & MAKE_FUNCTION_KWDEFAULTS) { - assert(PyDict_CheckExact(kwdefaults)); - func_obj->func_kwdefaults = kwdefaults; - } - if (oparg & MAKE_FUNCTION_DEFAULTS) { - assert(PyTuple_CheckExact(defaults)); - func_obj->func_defaults = defaults; - } - func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; } + inst(SET_FUNCTION_ATTRIBUTE, (attr, func -- func)) { + assert(PyFunction_Check(func)); + PyFunctionObject *func_obj = (PyFunctionObject *)func; + switch(oparg) { + case MAKE_FUNCTION_CLOSURE: + assert(func_obj->func_closure == NULL); + func_obj->func_closure = attr; + break; + case MAKE_FUNCTION_ANNOTATIONS: + assert(func_obj->func_annotations == NULL); + func_obj->func_annotations = attr; + break; + case MAKE_FUNCTION_KWDEFAULTS: + assert(PyDict_CheckExact(attr)); + assert(func_obj->func_kwdefaults == NULL); + func_obj->func_kwdefaults = attr; + break; + case MAKE_FUNCTION_DEFAULTS: + assert(PyTuple_CheckExact(attr)); + assert(func_obj->func_defaults == NULL); + func_obj->func_defaults = attr; + break; + default: + Py_UNREACHABLE(); + } + } + inst(RETURN_GENERATOR, (--)) { assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; diff --git a/Python/compile.c b/Python/compile.c index 68b0466d95801b..589d92f5a7e505 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1823,7 +1823,21 @@ compiler_make_closure(struct compiler *c, location loc, ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); } ADDOP_LOAD_CONST(c, loc, (PyObject*)co); - ADDOP_I(c, loc, MAKE_FUNCTION, flags); + + ADDOP(c, loc, MAKE_FUNCTION); + + if (flags & MAKE_FUNCTION_CLOSURE) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_CLOSURE); + } + if (flags & MAKE_FUNCTION_ANNOTATIONS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_ANNOTATIONS); + } + if (flags & MAKE_FUNCTION_KWDEFAULTS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_KWDEFAULTS); + } + if (flags & MAKE_FUNCTION_DEFAULTS) { + ADDOP_I(c, loc, SET_FUNCTION_ATTRIBUTE, MAKE_FUNCTION_DEFAULTS); + } return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b1b93c1d4d5f4c..ec0ba23090a014 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 138 "Python/bytecodes.c" + #line 137 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 152 "Python/bytecodes.c" + #line 151 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? @@ -57,7 +57,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 180 "Python/bytecodes.c" + #line 179 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -70,7 +70,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 187 "Python/bytecodes.c" + #line 186 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -82,7 +82,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 193 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 199 "Python/bytecodes.c" + #line 198 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -107,7 +107,7 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 205 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); @@ -123,7 +123,7 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 214 "Python/bytecodes.c" + #line 213 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 130 "Python/generated_cases.c.h" @@ -134,7 +134,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 219 "Python/bytecodes.c" + #line 218 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 140 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -144,7 +144,7 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 227 "Python/bytecodes.c" + #line 226 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -158,7 +158,7 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 235 "Python/bytecodes.c" + #line 234 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -170,7 +170,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 242 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 175 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -179,7 +179,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 246 "Python/bytecodes.c" + #line 245 "Python/bytecodes.c" res = NULL; #line 185 "Python/generated_cases.c.h" STACK_GROW(1); @@ -192,13 +192,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 242 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 197 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 242 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 203 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -209,7 +209,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 252 "Python/bytecodes.c" + #line 251 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -229,7 +229,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 265 "Python/bytecodes.c" + #line 264 "Python/bytecodes.c" Py_DECREF(receiver); #line 235 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -240,7 +240,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 269 "Python/bytecodes.c" + #line 268 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -258,11 +258,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 280 "Python/bytecodes.c" + #line 279 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 264 "Python/generated_cases.c.h" Py_DECREF(value); - #line 282 "Python/bytecodes.c" + #line 281 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 268 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -272,11 +272,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 286 "Python/bytecodes.c" + #line 285 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 278 "Python/generated_cases.c.h" Py_DECREF(value); - #line 288 "Python/bytecodes.c" + #line 287 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -292,11 +292,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 298 "Python/bytecodes.c" + #line 297 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 298 "Python/generated_cases.c.h" Py_DECREF(value); - #line 300 "Python/bytecodes.c" + #line 299 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 302 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -309,7 +309,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 316 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 316 "Python/generated_cases.c.h" @@ -320,7 +320,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 321 "Python/bytecodes.c" + #line 320 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -341,7 +341,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 316 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 348 "Python/generated_cases.c.h" @@ -352,7 +352,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 329 "Python/bytecodes.c" + #line 328 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -373,7 +373,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 316 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 380 "Python/generated_cases.c.h" @@ -384,7 +384,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 337 "Python/bytecodes.c" + #line 336 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -405,7 +405,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 352 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 412 "Python/generated_cases.c.h" @@ -416,7 +416,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 357 "Python/bytecodes.c" + #line 356 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -437,7 +437,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 352 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 444 "Python/generated_cases.c.h" @@ -448,7 +448,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 365 "Python/bytecodes.c" + #line 364 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -469,7 +469,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 352 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 476 "Python/generated_cases.c.h" @@ -480,7 +480,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 373 "Python/bytecodes.c" + #line 372 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -501,7 +501,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 388 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 508 "Python/generated_cases.c.h" @@ -512,7 +512,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 393 "Python/bytecodes.c" + #line 392 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -533,7 +533,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 388 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 540 "Python/generated_cases.c.h" @@ -543,7 +543,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 410 "Python/bytecodes.c" + #line 409 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -579,7 +579,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 447 "Python/bytecodes.c" + #line 446 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -594,7 +594,7 @@ #line 595 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 459 "Python/bytecodes.c" + #line 458 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 600 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -608,7 +608,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 463 "Python/bytecodes.c" + #line 462 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -632,7 +632,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 478 "Python/bytecodes.c" + #line 477 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -654,7 +654,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 493 "Python/bytecodes.c" + #line 492 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -679,7 +679,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 509 "Python/bytecodes.c" + #line 508 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -704,7 +704,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 525 "Python/bytecodes.c" + #line 524 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -715,7 +715,7 @@ #line 716 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 533 "Python/bytecodes.c" + #line 532 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -731,7 +731,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 540 "Python/bytecodes.c" + #line 539 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -760,7 +760,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 565 "Python/bytecodes.c" + #line 564 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -770,11 +770,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 569 "Python/bytecodes.c" + #line 568 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 776 "Python/generated_cases.c.h" Py_DECREF(v); - #line 571 "Python/bytecodes.c" + #line 570 "Python/bytecodes.c" if (err) goto pop_1_error; #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -788,7 +788,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 581 "Python/bytecodes.c" + #line 580 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -807,7 +807,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 596 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" if (err) goto pop_3_error; #line 813 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -819,7 +819,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 600 "Python/bytecodes.c" + #line 599 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -846,7 +846,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 619 "Python/bytecodes.c" + #line 618 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -861,13 +861,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 627 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 868 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 630 "Python/bytecodes.c" + #line 629 "Python/bytecodes.c" if (err) goto pop_2_error; #line 873 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -877,12 +877,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 634 "Python/bytecodes.c" + #line 633 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 884 "Python/generated_cases.c.h" Py_DECREF(value); - #line 637 "Python/bytecodes.c" + #line 636 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 888 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -893,13 +893,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 641 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 900 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 644 "Python/bytecodes.c" + #line 643 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 905 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -909,7 +909,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 648 "Python/bytecodes.c" + #line 647 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -932,7 +932,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 668 "Python/bytecodes.c" + #line 667 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -948,7 +948,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 681 "Python/bytecodes.c" + #line 680 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -966,7 +966,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 696 "Python/bytecodes.c" + #line 695 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -987,7 +987,7 @@ } TARGET(RETURN_CONST) { - #line 715 "Python/bytecodes.c" + #line 714 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1005,7 +1005,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 731 "Python/bytecodes.c" + #line 730 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1029,7 +1029,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 751 "Python/bytecodes.c" + #line 750 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1044,14 +1044,14 @@ type->tp_name); #line 1046 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 764 "Python/bytecodes.c" + #line 763 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1053 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 769 "Python/bytecodes.c" + #line 768 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1072,7 +1072,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 784 "Python/bytecodes.c" + #line 783 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1124,7 +1124,7 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 829 "Python/bytecodes.c" + #line 828 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1133,7 +1133,7 @@ #line 1135 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 836 "Python/bytecodes.c" + #line 835 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1161,7 +1161,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 860 "Python/bytecodes.c" + #line 859 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1217,7 +1217,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 909 "Python/bytecodes.c" + #line 908 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1238,7 +1238,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 927 "Python/bytecodes.c" + #line 926 "Python/bytecodes.c" assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1260,7 +1260,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 946 "Python/bytecodes.c" + #line 945 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1281,7 +1281,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 964 "Python/bytecodes.c" + #line 963 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1288 "Python/generated_cases.c.h" @@ -1292,7 +1292,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 969 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1316,13 +1316,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 989 "Python/bytecodes.c" + #line 988 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1323 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 992 "Python/bytecodes.c" + #line 991 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1340,7 +1340,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1001 "Python/bytecodes.c" + #line 1000 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1349,7 +1349,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1006 "Python/bytecodes.c" + #line 1005 "Python/bytecodes.c" none = Py_None; } else { @@ -1365,7 +1365,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1015 "Python/bytecodes.c" + #line 1014 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1371 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1375,7 +1375,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1019 "Python/bytecodes.c" + #line 1018 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1405,7 +1405,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1044 "Python/bytecodes.c" + #line 1043 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1414,7 +1414,7 @@ "no locals found when storing %R", name); #line 1416 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1051 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1423,7 +1423,7 @@ err = PyObject_SetItem(ns, name, v); #line 1425 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1058 "Python/bytecodes.c" + #line 1057 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1429 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1431,7 +1431,7 @@ } TARGET(DELETE_NAME) { - #line 1062 "Python/bytecodes.c" + #line 1061 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1456,7 +1456,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1088 "Python/bytecodes.c" + #line 1087 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1471,7 +1471,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1101 "Python/bytecodes.c" + #line 1100 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1477 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1483,7 +1483,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1105 "Python/bytecodes.c" + #line 1104 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1501,7 +1501,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1115 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1520,7 +1520,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1126 "Python/bytecodes.c" + #line 1125 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1538,13 +1538,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1137 "Python/bytecodes.c" + #line 1136 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1546 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1141 "Python/bytecodes.c" + #line 1140 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1550 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1557,7 +1557,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1152 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); @@ -1576,7 +1576,7 @@ #line 1577 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1168 "Python/bytecodes.c" + #line 1167 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1582 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1586,12 +1586,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1172 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1593 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1175 "Python/bytecodes.c" + #line 1174 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1597 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1600,12 +1600,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1179 "Python/bytecodes.c" + #line 1178 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1607 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1182 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1611 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1613,7 +1613,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1186 "Python/bytecodes.c" + #line 1185 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1633,7 +1633,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1200 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1653,7 +1653,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1200 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1667,7 +1667,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1212 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1737,7 +1737,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1212 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1806,7 +1806,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1281 "Python/bytecodes.c" + #line 1280 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1872,7 +1872,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1335 "Python/bytecodes.c" + #line 1334 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1898,7 +1898,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1348 "Python/bytecodes.c" + #line 1347 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1923,7 +1923,7 @@ } TARGET(DELETE_FAST) { - #line 1365 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1932,7 +1932,7 @@ } TARGET(MAKE_CELL) { - #line 1371 "Python/bytecodes.c" + #line 1370 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1946,7 +1946,7 @@ } TARGET(DELETE_DEREF) { - #line 1382 "Python/bytecodes.c" + #line 1381 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1964,7 +1964,7 @@ TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1395 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -2006,7 +2006,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1432 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2022,7 +2022,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1442 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -2033,7 +2033,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1449 "Python/bytecodes.c" + #line 1448 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2051,13 +2051,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1462 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2057 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1464 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2069,7 +2069,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1468 "Python/bytecodes.c" + #line 1467 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2076 "Python/generated_cases.c.h" @@ -2082,7 +2082,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1473 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2089 "Python/generated_cases.c.h" @@ -2095,7 +2095,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1478 "Python/bytecodes.c" + #line 1477 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2108,7 +2108,7 @@ } #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1489 "Python/bytecodes.c" + #line 1488 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -2121,11 +2121,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1496 "Python/bytecodes.c" + #line 1495 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2127 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1498 "Python/bytecodes.c" + #line 1497 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2131 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2135,7 +2135,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1502 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2160,7 +2160,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1519 "Python/bytecodes.c" + #line 1518 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2172,7 +2172,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1527 "Python/bytecodes.c" + #line 1526 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -2182,7 +2182,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1531 "Python/bytecodes.c" + #line 1530 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2230,7 +2230,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1573 "Python/bytecodes.c" + #line 1572 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2245,7 +2245,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1583 "Python/bytecodes.c" + #line 1582 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2255,7 +2255,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1587 "Python/bytecodes.c" + #line 1586 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2265,7 +2265,7 @@ } #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1595 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2272 "Python/generated_cases.c.h" @@ -2276,14 +2276,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1601 "Python/bytecodes.c" + #line 1600 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2285 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1606 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2290 "Python/generated_cases.c.h" @@ -2295,7 +2295,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1612 "Python/bytecodes.c" + #line 1611 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2307,7 +2307,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1620 "Python/bytecodes.c" + #line 1619 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -2324,7 +2324,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1634 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2370,7 +2370,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1676 "Python/bytecodes.c" + #line 1675 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2390,7 +2390,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1695 "Python/bytecodes.c" + #line 1694 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2401,7 +2401,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1702 "Python/bytecodes.c" + #line 1701 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2407 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -2418,7 +2418,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1706 "Python/bytecodes.c" + #line 1705 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2455,7 +2455,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1745 "Python/bytecodes.c" + #line 1744 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2491,7 +2491,7 @@ */ #line 2493 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1779 "Python/bytecodes.c" + #line 1778 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2502,7 +2502,7 @@ res = PyObject_GetAttr(owner, name); #line 2504 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1788 "Python/bytecodes.c" + #line 1787 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2509 "Python/generated_cases.c.h" @@ -2519,7 +2519,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1797 "Python/bytecodes.c" + #line 1796 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2547,7 +2547,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1813 "Python/bytecodes.c" + #line 1812 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2575,7 +2575,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1829 "Python/bytecodes.c" + #line 1828 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2617,7 +2617,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1859 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2642,7 +2642,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1872 "Python/bytecodes.c" + #line 1871 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2668,7 +2668,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1887 "Python/bytecodes.c" + #line 1886 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2700,7 +2700,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1913 "Python/bytecodes.c" + #line 1912 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2734,7 +2734,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1941 "Python/bytecodes.c" + #line 1940 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2763,7 +2763,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1961 "Python/bytecodes.c" + #line 1960 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2813,7 +2813,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2002 "Python/bytecodes.c" + #line 2001 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2835,7 +2835,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2021 "Python/bytecodes.c" + #line 2020 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2851,7 +2851,7 @@ #line 2852 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2034 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2857 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2864,7 +2864,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2038 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2886,7 +2886,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2052 "Python/bytecodes.c" + #line 2051 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2912,7 +2912,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2070 "Python/bytecodes.c" + #line 2069 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2935,12 +2935,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2084 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2941 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2086 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2952,12 +2952,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2090 "Python/bytecodes.c" + #line 2089 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2958 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2092 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 2964 "Python/generated_cases.c.h" @@ -2971,12 +2971,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2097 "Python/bytecodes.c" + #line 2096 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2977 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2099 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2987,7 +2987,7 @@ #line 2988 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2107 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3006,19 +3006,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2118 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3013 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2121 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3020 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2126 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3024 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3029,13 +3029,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2130 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3036 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2133 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3046,7 +3046,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2137 "Python/bytecodes.c" + #line 2136 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3057,14 +3057,14 @@ } TARGET(JUMP_FORWARD) { - #line 2143 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" JUMPBY(oparg); #line 3063 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2147 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3087,7 +3087,7 @@ } TARGET(ENTER_EXECUTOR) { - #line 2177 "Python/bytecodes.c" + #line 2176 "Python/bytecodes.c" _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); @@ -3101,7 +3101,7 @@ TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2188 "Python/bytecodes.c" + #line 2187 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } @@ -3109,7 +3109,7 @@ int err = PyObject_IsTrue(cond); #line 3111 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2194 "Python/bytecodes.c" + #line 2193 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3124,7 +3124,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2204 "Python/bytecodes.c" + #line 2203 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } @@ -3132,7 +3132,7 @@ int err = PyObject_IsTrue(cond); #line 3134 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2210 "Python/bytecodes.c" + #line 2209 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3147,11 +3147,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2220 "Python/bytecodes.c" + #line 2219 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3153 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2222 "Python/bytecodes.c" + #line 2221 "Python/bytecodes.c" JUMPBY(oparg); } #line 3158 "Python/generated_cases.c.h" @@ -3161,14 +3161,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2227 "Python/bytecodes.c" + #line 2226 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3170 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2232 "Python/bytecodes.c" + #line 2231 "Python/bytecodes.c" } #line 3174 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3176,7 +3176,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2236 "Python/bytecodes.c" + #line 2235 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3190,7 +3190,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2245 "Python/bytecodes.c" + #line 2244 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3207,7 +3207,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2253 "Python/bytecodes.c" + #line 2252 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3216,7 +3216,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2258 "Python/bytecodes.c" + #line 2257 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3233,7 +3233,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2268 "Python/bytecodes.c" + #line 2267 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3240 "Python/generated_cases.c.h" @@ -3245,7 +3245,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2273 "Python/bytecodes.c" + #line 2272 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3252 "Python/generated_cases.c.h" @@ -3258,7 +3258,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2278 "Python/bytecodes.c" + #line 2277 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -3271,12 +3271,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2284 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3278 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2287 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3282 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3286,7 +3286,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2291 "Python/bytecodes.c" + #line 2290 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3311,7 +3311,7 @@ } #line 3313 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2314 "Python/bytecodes.c" + #line 2313 "Python/bytecodes.c" } #line 3317 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3323,7 +3323,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2332 "Python/bytecodes.c" + #line 2331 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3362,7 +3362,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2365 "Python/bytecodes.c" + #line 2364 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3395,7 +3395,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2393 "Python/bytecodes.c" + #line 2392 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3425,7 +3425,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2415 "Python/bytecodes.c" + #line 2414 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3455,7 +3455,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2437 "Python/bytecodes.c" + #line 2436 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3482,7 +3482,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2457 "Python/bytecodes.c" + #line 2456 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3505,7 +3505,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2475 "Python/bytecodes.c" + #line 2474 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3530,7 +3530,7 @@ } #line 3532 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2498 "Python/bytecodes.c" + #line 2497 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3548,7 +3548,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2507 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3576,7 +3576,7 @@ } #line 3578 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2533 "Python/bytecodes.c" + #line 2532 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3595,7 +3595,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2542 "Python/bytecodes.c" + #line 2541 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3625,7 +3625,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2581 "Python/bytecodes.c" + #line 2580 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3649,7 +3649,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2593 "Python/bytecodes.c" + #line 2592 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3680,7 +3680,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2612 "Python/bytecodes.c" + #line 2611 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3704,7 +3704,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2624 "Python/bytecodes.c" + #line 2623 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3727,7 +3727,7 @@ } TARGET(KW_NAMES) { - #line 2640 "Python/bytecodes.c" + #line 2639 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); @@ -3736,7 +3736,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2646 "Python/bytecodes.c" + #line 2645 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3759,7 +3759,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2691 "Python/bytecodes.c" + #line 2690 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3853,7 +3853,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2779 "Python/bytecodes.c" + #line 2778 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3872,7 +3872,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2791 "Python/bytecodes.c" + #line 2790 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3906,7 +3906,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2819 "Python/bytecodes.c" + #line 2818 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3950,7 +3950,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2857 "Python/bytecodes.c" + #line 2856 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3973,7 +3973,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2869 "Python/bytecodes.c" + #line 2868 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3998,7 +3998,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2883 "Python/bytecodes.c" + #line 2882 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4023,7 +4023,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2897 "Python/bytecodes.c" + #line 2896 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4059,7 +4059,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2922 "Python/bytecodes.c" + #line 2921 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4101,7 +4101,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2953 "Python/bytecodes.c" + #line 2952 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4147,7 +4147,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2988 "Python/bytecodes.c" + #line 2987 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4193,7 +4193,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3023 "Python/bytecodes.c" + #line 3022 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4231,7 +4231,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3050 "Python/bytecodes.c" + #line 3049 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4270,7 +4270,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3080 "Python/bytecodes.c" + #line 3079 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4295,7 +4295,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3100 "Python/bytecodes.c" + #line 3099 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4339,7 +4339,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3134 "Python/bytecodes.c" + #line 3133 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4381,7 +4381,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3166 "Python/bytecodes.c" + #line 3165 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4423,7 +4423,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3198 "Python/bytecodes.c" + #line 3197 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4461,7 +4461,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3229 "Python/bytecodes.c" + #line 3228 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4467 "Python/generated_cases.c.h" } @@ -4472,7 +4472,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3233 "Python/bytecodes.c" + #line 3232 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4538,7 +4538,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3295 "Python/bytecodes.c" + #line 3294 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4545 "Python/generated_cases.c.h" @@ -4551,12 +4551,8 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; - PyObject *closure = (oparg & MAKE_FUNCTION_CLOSURE) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0))] : NULL; - PyObject *annotations = (oparg & MAKE_FUNCTION_ANNOTATIONS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0))] : NULL; - PyObject *kwdefaults = (oparg & MAKE_FUNCTION_KWDEFAULTS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0))] : NULL; - PyObject *defaults = (oparg & MAKE_FUNCTION_DEFAULTS) ? stack_pointer[-(1 + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_DEFAULTS) ? 1 : 0))] : NULL; PyObject *func; - #line 3305 "Python/bytecodes.c" + #line 3300 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4566,33 +4562,49 @@ goto error; } - if (oparg & MAKE_FUNCTION_CLOSURE) { - assert(PyTuple_CheckExact(closure)); - func_obj->func_closure = closure; - } - if (oparg & MAKE_FUNCTION_ANNOTATIONS) { - assert(PyTuple_CheckExact(annotations)); - func_obj->func_annotations = annotations; - } - if (oparg & MAKE_FUNCTION_KWDEFAULTS) { - assert(PyDict_CheckExact(kwdefaults)); - func_obj->func_kwdefaults = kwdefaults; - } - if (oparg & MAKE_FUNCTION_DEFAULTS) { - assert(PyTuple_CheckExact(defaults)); - func_obj->func_defaults = defaults; - } - func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4589 "Python/generated_cases.c.h" - STACK_SHRINK(((oparg & MAKE_FUNCTION_DEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0)); + #line 4568 "Python/generated_cases.c.h" + stack_pointer[-1] = func; + DISPATCH(); + } + + TARGET(SET_FUNCTION_ATTRIBUTE) { + PyObject *func = stack_pointer[-1]; + PyObject *attr = stack_pointer[-2]; + #line 3314 "Python/bytecodes.c" + assert(PyFunction_Check(func)); + PyFunctionObject *func_obj = (PyFunctionObject *)func; + switch(oparg) { + case MAKE_FUNCTION_CLOSURE: + assert(func_obj->func_closure == NULL); + func_obj->func_closure = attr; + break; + case MAKE_FUNCTION_ANNOTATIONS: + assert(func_obj->func_annotations == NULL); + func_obj->func_annotations = attr; + break; + case MAKE_FUNCTION_KWDEFAULTS: + assert(PyDict_CheckExact(attr)); + assert(func_obj->func_kwdefaults == NULL); + func_obj->func_kwdefaults = attr; + break; + case MAKE_FUNCTION_DEFAULTS: + assert(PyTuple_CheckExact(attr)); + assert(func_obj->func_defaults == NULL); + func_obj->func_defaults = attr; + break; + default: + Py_UNREACHABLE(); + } + #line 4601 "Python/generated_cases.c.h" + STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3336 "Python/bytecodes.c" + #line 3341 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4613,7 +4625,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4617 "Python/generated_cases.c.h" + #line 4629 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4621,15 +4633,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3359 "Python/bytecodes.c" + #line 3364 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4627 "Python/generated_cases.c.h" + #line 4639 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3361 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4633 "Python/generated_cases.c.h" + #line 4645 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4640,7 +4652,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3365 "Python/bytecodes.c" + #line 3370 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4675,7 +4687,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4679 "Python/generated_cases.c.h" + #line 4691 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4684,10 +4696,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3402 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4691 "Python/generated_cases.c.h" + #line 4703 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4699,7 +4711,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3407 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4714,12 +4726,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4718 "Python/generated_cases.c.h" + #line 4730 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3422 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4723 "Python/generated_cases.c.h" + #line 4735 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4729,16 +4741,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3427 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" assert(oparg >= 2); - #line 4735 "Python/generated_cases.c.h" + #line 4747 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3431 "Python/bytecodes.c" + #line 3436 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4750,26 +4762,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4754 "Python/generated_cases.c.h" + #line 4766 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3445 "Python/bytecodes.c" + #line 3450 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4760 "Python/generated_cases.c.h" + #line 4772 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3449 "Python/bytecodes.c" + #line 3454 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4767 "Python/generated_cases.c.h" + #line 4779 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3454 "Python/bytecodes.c" + #line 3459 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4778,12 +4790,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4782 "Python/generated_cases.c.h" + #line 4794 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3465 "Python/bytecodes.c" + #line 3470 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4792,12 +4804,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4796 "Python/generated_cases.c.h" + #line 4808 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3476 "Python/bytecodes.c" + #line 3481 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4809,12 +4821,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4813 "Python/generated_cases.c.h" + #line 4825 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3490 "Python/bytecodes.c" + #line 3495 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4826,30 +4838,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4830 "Python/generated_cases.c.h" + #line 4842 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3504 "Python/bytecodes.c" + #line 3509 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4841 "Python/generated_cases.c.h" + #line 4853 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3512 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4848 "Python/generated_cases.c.h" + #line 4860 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3517 "Python/bytecodes.c" + #line 3522 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4855 "Python/generated_cases.c.h" + #line 4867 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index cbe38617c7a087..7c0cbdb35e0605 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -395,7 +395,9 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { case CALL_FUNCTION_EX: return ((oparg & 1) ? 1 : 0) + 3; case MAKE_FUNCTION: - return ((oparg & MAKE_FUNCTION_DEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_KWDEFAULTS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_ANNOTATIONS) ? 1 : 0) + ((oparg & MAKE_FUNCTION_CLOSURE) ? 1 : 0) + 1; + return 1; + case SET_FUNCTION_ATTRIBUTE: + return 2; case RETURN_GENERATOR: return 0; case BUILD_SLICE: @@ -812,6 +814,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case MAKE_FUNCTION: return 1; + case SET_FUNCTION_ATTRIBUTE: + return 1; case RETURN_GENERATOR: return 0; case BUILD_SLICE: @@ -1049,7 +1053,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 }, [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IX }, + [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB }, [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, [BUILD_SLICE] = { true, INSTR_FMT_IB }, [FORMAT_VALUE] = { true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 02e6033867d661..e23c0f04da15c8 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -23,20 +23,21 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, - &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_MAKE_FUNCTION, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, + &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, @@ -47,7 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, - &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, - &&TARGET_COMPARE_OP_STR, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_COMPARE_OP_STR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_SUPER_ATTR_ATTR, - &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_RETURN_VALUE, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_LOCALS, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,7 +131,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_MAKE_FUNCTION, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, @@ -176,7 +176,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_INTRINSIC_2, &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, &&TARGET_LOAD_FROM_DICT_OR_DEREF, - &&_unknown_opcode, + &&TARGET_SET_FUNCTION_ATTRIBUTE, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, From c3d2d64b4c53203719466b32df60ea76f7312891 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 13 Jun 2023 10:34:27 +0100 Subject: [PATCH 012/446] Fix magic number (GH-105722) --- Lib/importlib/_bootstrap_external.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 1d27b74453224f..707dd7bb8b99cc 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -447,8 +447,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12b1 3531 (Add PEP 695 changes) # Python 3.13a1 3550 (Plugin optimizer support) # Python 3.13a1 3551 (Compact superinstructions) - -# Python 3.13a1 3554 (Add SET_FUNCTION_ATTRIBUTE) +# Python 3.13a1 3552 (Add SET_FUNCTION_ATTRIBUTE) # Python 3.14 will start with 3600 @@ -465,7 +464,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 = (3554).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3552).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c From ed8217b493e19cea0f3f539e55b592c09ceb9323 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 13 Jun 2023 12:39:29 +0200 Subject: [PATCH 013/446] gh-105713: Document that tokenize raises when mixing tabs/spaces (#105723) * gh-105713: Document that tokenize raises when mixing tabs/spaces * Update Doc/whatsnew/3.12.rst Co-authored-by: Alex Waygood --- Doc/whatsnew/3.12.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index f1c3f086463d75..bfbc6c7a35c6ff 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1499,6 +1499,9 @@ Changes in the Python API * Some incomplete or invalid Python code now raises :exc:`tokenize.TokenError` instead of returning arbitrary ``ERRORTOKEN`` tokens when tokenizing it. + * Mixing tabs and spaces as indentation in the same file is not supported anymore and will + raise a :exc:`TabError`. + Build Changes ============= From d0f1afd9425e28409fbf535bb7d43472bfcffcef Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Jun 2023 13:49:36 +0200 Subject: [PATCH 014/446] gh-105373: Remove PyArg_Parse() deprecation (#105394) There is no plan to deprecate PyArg_Parse(). The deprecation was added as a comment in the C API documentation in 2007 by commit 85eb8c103c9e460917911b43c6be302c30d75efb. --- Doc/c-api/arg.rst | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index b7cdf293d22380..d2ea490732fe59 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -439,16 +439,24 @@ API Functions .. versionadded:: 3.2 -.. XXX deprecated, will be removed .. c:function:: int PyArg_Parse(PyObject *args, const char *format, ...) - Function used to deconstruct the argument lists of "old-style" functions --- - these are functions which use the :const:`METH_OLDARGS` parameter parsing - method, which has been removed in Python 3. This is not recommended for use - in parameter parsing in new code, and most code in the standard interpreter - has been modified to no longer use this for that purpose. It does remain a - convenient way to decompose other tuples, however, and may continue to be - used for that purpose. + Parse the parameter of a function that takes a single positional parameter + into a local variable. Returns true on success; on failure, it returns + false and raises the appropriate exception. + + Example:: + + // Function using METH_O calling convention + static PyObject* + my_function(PyObject *module, PyObject *arg) + { + int value; + if (!PyArg_Parse(arg, "i:my_function", &value)) { + return NULL; + } + // ... use value ... + } .. c:function:: int PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) From abfbab6415fb029e7dca19ecc8d29a13da37bf71 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 13 Jun 2023 17:18:11 +0200 Subject: [PATCH 015/446] gh-105718: Fix buffer allocation in tokenizer with readline (#105728) --- Lib/test/test_tokenize.py | 10 ++++++++++ Parser/tokenizer.c | 4 ---- Parser/tokenizer.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index df9c9db322dc94..15f53632cff814 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -2239,6 +2239,16 @@ def test_string(self): FSTRING_START \'f"\' (1, 0) (1, 2) FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 2) (2, 3) FSTRING_END '"' (2, 3) (2, 4) + """) + + self.check_tokenize('''\ +f"{ +a}"''', """\ + FSTRING_START 'f"' (1, 0) (1, 2) + LBRACE '{' (1, 2) (1, 3) + NAME 'a' (2, 0) (2, 1) + RBRACE '}' (2, 1) (2, 2) + FSTRING_END '"' (2, 2) (2, 3) """) self.check_tokenize(r'Rf"abc\ diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index bf6bfd92d3a47d..5d01b8e8a5ac20 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1106,11 +1106,7 @@ tok_readline_string(struct tok_state* tok) { tok->inp += buflen; *tok->inp = '\0'; - if (tok->start == NULL) { - tok->buf = tok->cur; - } tok->line_start = tok->cur; - Py_DECREF(line); return 1; error: diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 16e919a8931edd..cb44845c1d306e 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -68,7 +68,7 @@ typedef struct _tokenizer_mode { struct tok_state { /* Input state; buf <= cur <= inp <= end */ /* NB an entire line is held in the buffer */ - char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL */ + char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL or readline != NULL */ char *cur; /* Next character in buffer */ char *inp; /* End of data in buffer */ int fp_interactive; /* If the file descriptor is interactive */ From b97e14a806477af4225777d215ac38c0d9b845f0 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 13 Jun 2023 11:08:32 -0600 Subject: [PATCH 016/446] gh-105603: Change the PyInterpreterConfig.own gil Field (gh-105620) We are changing it to be more flexible that a strict bool can be for possible future expanded used cases. --- Include/cpython/initconfig.h | 10 +++++++--- Lib/test/support/__init__.py | 5 ++++- Lib/test/test_import/__init__.py | 3 ++- ...-06-09-19-16-57.gh-issue-105603.-z6G22.rst | 5 +++++ Modules/_testcapimodule.c | 14 +++++++------- Python/pylifecycle.c | 19 +++++++++++++++---- 6 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index efae2409b50069..c103c2026e40e9 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -244,6 +244,10 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config, /* --- PyInterpreterConfig ------------------------------------ */ +#define PyInterpreterConfig_DEFAULT_GIL (0) +#define PyInterpreterConfig_SHARED_GIL (1) +#define PyInterpreterConfig_OWN_GIL (2) + typedef struct { // XXX "allow_object_sharing"? "own_objects"? int use_main_obmalloc; @@ -252,7 +256,7 @@ typedef struct { int allow_threads; int allow_daemon_threads; int check_multi_interp_extensions; - int own_gil; + int gil; } PyInterpreterConfig; #define _PyInterpreterConfig_INIT \ @@ -263,7 +267,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 0, \ .check_multi_interp_extensions = 1, \ - .own_gil = 1, \ + .gil = PyInterpreterConfig_OWN_GIL, \ } #define _PyInterpreterConfig_LEGACY_INIT \ @@ -274,7 +278,7 @@ typedef struct { .allow_threads = 1, \ .allow_daemon_threads = 1, \ .check_multi_interp_extensions = 0, \ - .own_gil = 0, \ + .gil = PyInterpreterConfig_SHARED_GIL, \ } /* --- Helper functions --------------------------------------- */ diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 0b5ff3a5cf545b..3b332f49951f0c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1813,13 +1813,16 @@ def run_in_subinterp(code): return _testcapi.run_in_subinterp(code) -def run_in_subinterp_with_config(code, **config): +def run_in_subinterp_with_config(code, *, own_gil=None, **config): """ Run code in a subinterpreter. Raise unittest.SkipTest if the tracemalloc module is enabled. """ _check_tracemalloc() import _testcapi + if own_gil is not None: + assert 'gil' not in config, (own_gil, config) + config['gil'] = 2 if own_gil else 1 return _testcapi.run_in_subinterp_with_config(code, **config) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 227c912bc8c322..71a50bcbeedf9b 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1640,9 +1640,10 @@ class SubinterpImportTests(unittest.TestCase): ) ISOLATED = dict( use_main_obmalloc=False, - own_gil=True, + gil=2, ) NOT_ISOLATED = {k: not v for k, v in ISOLATED.items()} + NOT_ISOLATED['gil'] = 1 @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()") def pipe(self): diff --git a/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst b/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst new file mode 100644 index 00000000000000..cd3d9bcdd4e285 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-09-19-16-57.gh-issue-105603.-z6G22.rst @@ -0,0 +1,5 @@ +We've renamed the new (in 3.12) ``PyInterpreterConfig.own_gil`` to +``PyInterpreterConfig.gil`` and changed the meaning of the value from "bool" +to an integer with supported values of ``PyInterpreterConfig_DEFAULT_GIL``, +``PyInterpreterConfig_SHARED_GIL``, and ``PyInterpreterConfig_OWN_GIL``. The +default is "shared". diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3acc7575cfe8db..35687b49f24a0d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1426,7 +1426,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) int allow_threads = -1; int allow_daemon_threads = -1; int check_multi_interp_extensions = -1; - int own_gil = -1; + int gil = -1; int r; PyThreadState *substate, *mainstate; /* only initialise 'cflags.cf_flags' to test backwards compatibility */ @@ -1439,15 +1439,15 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) "allow_threads", "allow_daemon_threads", "check_multi_interp_extensions", - "own_gil", + "gil", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "s$ppppppp:run_in_subinterp_with_config", kwlist, + "s$ppppppi:run_in_subinterp_with_config", kwlist, &code, &use_main_obmalloc, &allow_fork, &allow_exec, &allow_threads, &allow_daemon_threads, &check_multi_interp_extensions, - &own_gil)) { + &gil)) { return NULL; } if (use_main_obmalloc < 0) { @@ -1466,8 +1466,8 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) PyErr_SetString(PyExc_ValueError, "missing allow_threads"); return NULL; } - if (own_gil < 0) { - PyErr_SetString(PyExc_ValueError, "missing own_gil"); + if (gil < 0) { + PyErr_SetString(PyExc_ValueError, "missing gil"); return NULL; } if (allow_daemon_threads < 0) { @@ -1490,7 +1490,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_threads = allow_threads, .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, - .own_gil = own_gil, + .gil = gil, }; PyStatus status = Py_NewInterpreterFromConfig(&substate, &config); if (PyStatus_Exception(status)) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 9ac5630959f8f5..9ae03d4d783117 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -578,12 +578,14 @@ init_interp_settings(PyInterpreterState *interp, interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS; } + /* We check "gil" in init_interp_create_gil(). */ + return _PyStatus_OK(); } static PyStatus -init_interp_create_gil(PyThreadState *tstate, int own_gil) +init_interp_create_gil(PyThreadState *tstate, int gil) { PyStatus status; @@ -598,6 +600,15 @@ init_interp_create_gil(PyThreadState *tstate, int own_gil) return status; } + int own_gil; + switch (gil) { + case PyInterpreterConfig_DEFAULT_GIL: own_gil = 0; break; + case PyInterpreterConfig_SHARED_GIL: own_gil = 0; break; + case PyInterpreterConfig_OWN_GIL: own_gil = 1; break; + default: + return _PyStatus_ERR("invalid interpreter config 'gil' value"); + } + /* Create the GIL and take it */ status = _PyEval_InitGIL(tstate, own_gil); if (_PyStatus_EXCEPTION(status)) { @@ -633,7 +644,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; // The main interpreter always has its own GIL. - config.own_gil = 1; + config.gil = PyInterpreterConfig_OWN_GIL; status = init_interp_settings(interp, &config); if (_PyStatus_EXCEPTION(status)) { return status; @@ -647,7 +658,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, // XXX For now we do this before the GIL is created. (void) _PyThreadState_SwapNoGIL(tstate); - status = init_interp_create_gil(tstate, config.own_gil); + status = init_interp_create_gil(tstate, config.gil); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -2057,7 +2068,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config) goto error; } - status = init_interp_create_gil(tstate, config->own_gil); + status = init_interp_create_gil(tstate, config->gil); if (_PyStatus_EXCEPTION(status)) { goto error; } From 2211454fe210637ed7fabda12690dac6cc9a8149 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Jun 2023 20:16:26 +0200 Subject: [PATCH 017/446] gh-105733: Deprecate ctypes SetPointerType() and ARRAY() (#105734) --- Doc/whatsnew/3.13.rst | 6 +++++ Lib/ctypes/__init__.py | 6 +++-- Lib/test/test_ctypes/test_arrays.py | 19 +++++++++++++-- Lib/test/test_ctypes/test_incomplete.py | 23 +++++++++++++++---- ...-06-13-19-38-12.gh-issue-105733.WOp0mG.rst | 2 ++ 5 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-13-19-38-12.gh-issue-105733.WOp0mG.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index e6504b0152acc2..97bc1587d5052a 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -140,6 +140,12 @@ Deprecated Use the ``'w'`` format code instead. (contributed by Hugo van Kemenade in :gh:`80480`) +* :mod:`ctypes`: Deprecate undocumented :func:`!ctypes.SetPointerType` + and :func:`!ctypes.ARRAY` functions. + Replace ``ctypes.SetPointerType(item_type, size)`` with ``item_type * size``. + (Contributed by Victor Stinner in :gh:`105733`.) + + Removed ======= diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index 95353bab26cc71..141142a57dcb3e 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -302,8 +302,9 @@ def create_unicode_buffer(init, size=None): raise TypeError(init) -# XXX Deprecated def SetPointerType(pointer, cls): + import warnings + warnings._deprecated("ctypes.SetPointerType", remove=(3, 15)) if _pointer_type_cache.get(cls, None) is not None: raise RuntimeError("This type already exists in the cache") if id(pointer) not in _pointer_type_cache: @@ -312,8 +313,9 @@ def SetPointerType(pointer, cls): _pointer_type_cache[cls] = pointer del _pointer_type_cache[id(pointer)] -# XXX Deprecated def ARRAY(typ, len): + import warnings + warnings._deprecated("ctypes.ARRAY", remove=(3, 15)) return typ * len ################################################################ diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 415a5785a9c1bb..473083870ca6e5 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -1,7 +1,9 @@ -import unittest -from test.support import bigmemtest, _2G +import ctypes import sys +import unittest +import warnings from ctypes import * +from test.support import bigmemtest, _2G from test.test_ctypes import need_symbol @@ -10,6 +12,14 @@ formats = c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, \ c_long, c_ulonglong, c_float, c_double, c_longdouble + +def ARRAY(*args): + # ignore DeprecationWarning in tests + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return ctypes.ARRAY(*args) + + class ArrayTestCase(unittest.TestCase): def test_simple(self): # create classes holding simple numeric types, and check @@ -234,5 +244,10 @@ def test_bpo36504_signed_int_overflow(self): def test_large_array(self, size): c_char * size + def test_deprecation(self): + with self.assertWarns(DeprecationWarning): + CharArray = ctypes.ARRAY(c_char, 3) + + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_incomplete.py b/Lib/test/test_ctypes/test_incomplete.py index 00c430ef53cfa8..0b53c15f1f9986 100644 --- a/Lib/test/test_ctypes/test_incomplete.py +++ b/Lib/test/test_ctypes/test_incomplete.py @@ -1,4 +1,6 @@ +import ctypes import unittest +import warnings from ctypes import * ################################################################ @@ -6,7 +8,11 @@ # The incomplete pointer example from the tutorial # -class MyTestCase(unittest.TestCase): +class TestSetPointerType(unittest.TestCase): + + def tearDown(self): + # to not leak references, we must clean _pointer_type_cache + ctypes._reset_cache() def test_incomplete_example(self): lpcell = POINTER("cell") @@ -14,7 +20,9 @@ class cell(Structure): _fields_ = [("name", c_char_p), ("next", lpcell)] - SetPointerType(lpcell, cell) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + ctypes.SetPointerType(lpcell, cell) c1 = cell() c1.name = b"foo" @@ -32,9 +40,14 @@ class cell(Structure): p = p.next[0] self.assertEqual(result, [b"foo", b"bar"] * 4) - # to not leak references, we must clean _pointer_type_cache - from ctypes import _pointer_type_cache - del _pointer_type_cache[cell] + def test_deprecation(self): + lpcell = POINTER("cell") + class cell(Structure): + _fields_ = [("name", c_char_p), + ("next", lpcell)] + + with self.assertWarns(DeprecationWarning): + ctypes.SetPointerType(lpcell, cell) ################################################################ diff --git a/Misc/NEWS.d/next/Library/2023-06-13-19-38-12.gh-issue-105733.WOp0mG.rst b/Misc/NEWS.d/next/Library/2023-06-13-19-38-12.gh-issue-105733.WOp0mG.rst new file mode 100644 index 00000000000000..20f2ba2bcc5cb1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-13-19-38-12.gh-issue-105733.WOp0mG.rst @@ -0,0 +1,2 @@ +:mod:`ctypes`: Deprecate undocumented :func:`!ctypes.SetPointerType` and +:func:`!ctypes.ARRAY` functions. Patch by Victor Stinner. From be2779c0cb54e56ea4bb9822cc7bb5c24e6a7af7 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 13 Jun 2023 21:42:03 +0100 Subject: [PATCH 018/446] gh-105481: add flags to each instr in the opcode metadata table, to replace opcode.hasarg/hasname/hasconst (#105482) --- Python/bytecodes.c | 52 +- Python/ceval_macros.h | 5 + Python/compile.c | 2 + Python/generated_cases.c.h | 764 ++++++++++++------------ Python/opcode_metadata.h | 413 ++++++------- Tools/cases_generator/generate_cases.py | 66 +- 6 files changed, 679 insertions(+), 623 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index cd8b674370b7eb..2d9671f27edfe8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -210,7 +210,7 @@ dummy_func( } inst(LOAD_CONST, (-- value)) { - value = GETITEM(frame->f_code->co_consts, oparg); + value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); } @@ -711,7 +711,7 @@ dummy_func( } inst(RETURN_CONST, (--)) { - PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -727,7 +727,7 @@ dummy_func( } inst(INSTRUMENTED_RETURN_CONST, (--)) { - PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -924,6 +924,7 @@ dummy_func( inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) { assert(frame != &entry_frame); + assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); @@ -945,6 +946,7 @@ dummy_func( // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. + assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1040,7 +1042,7 @@ dummy_func( inst(STORE_NAME, (v -- )) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1058,7 +1060,7 @@ dummy_func( } inst(DELETE_NAME, (--)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1150,7 +1152,7 @@ dummy_func( inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) { #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1161,28 +1163,28 @@ dummy_func( #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_ATTR, (owner --)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); DECREF_INPUTS(); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_GLOBAL, (--)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1208,7 +1210,7 @@ dummy_func( macro(LOAD_LOCALS) = _LOAD_LOCALS; op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { @@ -1280,7 +1282,7 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1288,7 +1290,7 @@ dummy_func( STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1630,7 +1632,7 @@ dummy_func( }; inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; @@ -1695,7 +1697,7 @@ dummy_func( DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); DECREF_INPUTS(); ERROR_IF(res == NULL, error); @@ -1706,7 +1708,7 @@ dummy_func( DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, @@ -1744,7 +1746,7 @@ dummy_func( #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1752,7 +1754,7 @@ dummy_func( STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -1834,7 +1836,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -1922,7 +1924,7 @@ dummy_func( DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -1966,7 +1968,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -2126,14 +2128,14 @@ dummy_func( } inst(IMPORT_NAME, (level, fromlist -- res)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(IMPORT_FROM, (from -- from, res)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); } @@ -2637,8 +2639,8 @@ dummy_func( inst(KW_NAMES, (--)) { assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); - kwnames = GETITEM(frame->f_code->co_consts, oparg); + assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); + kwnames = GETITEM(FRAME_CO_CONSTS, oparg); } inst(INSTRUMENTED_CALL, ( -- )) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 44d6ee8656924a..6f6fabc37efd6a 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -219,6 +219,11 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define STACK_SHRINK(n) BASIC_STACKADJ(-(n)) #endif + +/* Data access macros */ +#define FRAME_CO_CONSTS (frame->f_code->co_consts) +#define FRAME_CO_NAMES (frame->f_code->co_names) + /* Local variable macros */ #define GETLOCAL(i) (frame->localsplus[i]) diff --git a/Python/compile.c b/Python/compile.c index 589d92f5a7e505..399a702ac1d7eb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -248,6 +248,8 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) { static int instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { + assert(!HAS_ARG(opcode) == !OPCODE_HAS_ARG(opcode)); + assert(!HAS_CONST(opcode) == !OPCODE_HAS_CONST(opcode)); assert(0 <= opcode && opcode <= MAX_OPCODE); assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode)); assert(IS_WITHIN_OPCODE_RANGE(opcode)); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ec0ba23090a014..ef4c921f19a6f8 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -124,7 +124,7 @@ TARGET(LOAD_CONST) { PyObject *value; #line 213 "Python/bytecodes.c" - value = GETITEM(frame->f_code->co_consts, oparg); + value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 130 "Python/generated_cases.c.h" STACK_GROW(1); @@ -988,7 +988,7 @@ TARGET(RETURN_CONST) { #line 714 "Python/bytecodes.c" - PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1006,7 +1006,7 @@ TARGET(INSTRUMENTED_RETURN_CONST) { #line 730 "Python/bytecodes.c" - PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); + PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -1240,6 +1240,7 @@ PyObject *retval = stack_pointer[-1]; #line 926 "Python/bytecodes.c" assert(frame != &entry_frame); + assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; _PyFrame_SetStackPointer(frame, stack_pointer - 1); @@ -1255,15 +1256,16 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1259 "Python/generated_cases.c.h" + #line 1260 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 945 "Python/bytecodes.c" + #line 946 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. + assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ assert(frame != &entry_frame); PyGenObject *gen = _PyFrame_GetGenerator(frame); gen->gi_frame_state = FRAME_SUSPENDED; @@ -1276,15 +1278,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1280 "Python/generated_cases.c.h" + #line 1282 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 963 "Python/bytecodes.c" + #line 965 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1288 "Python/generated_cases.c.h" + #line 1290 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1292,7 +1294,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 968 "Python/bytecodes.c" + #line 970 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1310,26 +1312,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1314 "Python/generated_cases.c.h" + #line 1316 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 988 "Python/bytecodes.c" + #line 990 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1323 "Python/generated_cases.c.h" + #line 1325 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 991 "Python/bytecodes.c" + #line 993 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1333 "Python/generated_cases.c.h" + #line 1335 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1340,23 +1342,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1000 "Python/bytecodes.c" + #line 1002 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1349 "Python/generated_cases.c.h" + #line 1351 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1005 "Python/bytecodes.c" + #line 1007 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1360 "Python/generated_cases.c.h" + #line 1362 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1365,9 +1367,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1014 "Python/bytecodes.c" + #line 1016 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1371 "Python/generated_cases.c.h" + #line 1373 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1375,7 +1377,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1018 "Python/bytecodes.c" + #line 1020 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1397,7 +1399,7 @@ if (true) goto error; } } - #line 1401 "Python/generated_cases.c.h" + #line 1403 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1405,34 +1407,34 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1043 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1045 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1416 "Python/generated_cases.c.h" + #line 1418 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1050 "Python/bytecodes.c" + #line 1052 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1425 "Python/generated_cases.c.h" + #line 1427 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1057 "Python/bytecodes.c" + #line 1059 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1429 "Python/generated_cases.c.h" + #line 1431 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1061 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1063 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1448,7 +1450,7 @@ name); goto error; } - #line 1452 "Python/generated_cases.c.h" + #line 1454 "Python/generated_cases.c.h" DISPATCH(); } @@ -1456,7 +1458,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1087 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1469,11 +1471,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1473 "Python/generated_cases.c.h" + #line 1475 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1100 "Python/bytecodes.c" + #line 1102 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1477 "Python/generated_cases.c.h" + #line 1479 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1483,14 +1485,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1104 "Python/bytecodes.c" + #line 1106 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1494 "Python/generated_cases.c.h" + #line 1496 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1501,7 +1503,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1114 "Python/bytecodes.c" + #line 1116 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1509,7 +1511,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1513 "Python/generated_cases.c.h" + #line 1515 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1520,7 +1522,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1125 "Python/bytecodes.c" + #line 1127 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1528,7 +1530,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1532 "Python/generated_cases.c.h" + #line 1534 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1538,15 +1540,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1136 "Python/bytecodes.c" + #line 1138 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1546 "Python/generated_cases.c.h" + #line 1548 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1140 "Python/bytecodes.c" + #line 1142 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1550 "Python/generated_cases.c.h" + #line 1552 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1557,10 +1559,10 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1151 "Python/bytecodes.c" + #line 1153 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1571,14 +1573,14 @@ #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1577 "Python/generated_cases.c.h" + #line 1579 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1167 "Python/bytecodes.c" + #line 1169 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1582 "Python/generated_cases.c.h" + #line 1584 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1586,35 +1588,35 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1171 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1173 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1593 "Python/generated_cases.c.h" + #line 1595 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1174 "Python/bytecodes.c" + #line 1176 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1597 "Python/generated_cases.c.h" + #line 1599 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1178 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1180 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1607 "Python/generated_cases.c.h" + #line 1609 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1181 "Python/bytecodes.c" + #line 1183 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1611 "Python/generated_cases.c.h" + #line 1613 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1185 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1187 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1625,7 +1627,7 @@ } goto error; } - #line 1629 "Python/generated_cases.c.h" + #line 1631 "Python/generated_cases.c.h" DISPATCH(); } @@ -1633,7 +1635,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1201 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1641,7 +1643,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1645 "Python/generated_cases.c.h" + #line 1647 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1653,7 +1655,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1201 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1661,14 +1663,14 @@ if (true) goto error; } Py_INCREF(locals); - #line 1665 "Python/generated_cases.c.h" + #line 1667 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1213 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { @@ -1724,7 +1726,7 @@ } } } - #line 1728 "Python/generated_cases.c.h" + #line 1730 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1737,8 +1739,8 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 1213 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); if (v != NULL) { @@ -1794,7 +1796,7 @@ } } } - #line 1798 "Python/generated_cases.c.h" + #line 1800 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1806,11 +1808,11 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1280 "Python/bytecodes.c" + #line 1282 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1818,7 +1820,7 @@ STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1858,7 +1860,7 @@ } } null = NULL; - #line 1862 "Python/generated_cases.c.h" + #line 1864 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1872,7 +1874,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1334 "Python/bytecodes.c" + #line 1336 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1883,7 +1885,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1887 "Python/generated_cases.c.h" + #line 1889 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1898,7 +1900,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1347 "Python/bytecodes.c" + #line 1349 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1913,7 +1915,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1917 "Python/generated_cases.c.h" + #line 1919 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1923,16 +1925,16 @@ } TARGET(DELETE_FAST) { - #line 1364 "Python/bytecodes.c" + #line 1366 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1931 "Python/generated_cases.c.h" + #line 1933 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1370 "Python/bytecodes.c" + #line 1372 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1941,12 +1943,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1945 "Python/generated_cases.c.h" + #line 1947 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1381 "Python/bytecodes.c" + #line 1383 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1957,14 +1959,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1961 "Python/generated_cases.c.h" + #line 1963 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1394 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1999,14 +2001,14 @@ } Py_INCREF(value); } - #line 2003 "Python/generated_cases.c.h" + #line 2005 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1431 "Python/bytecodes.c" + #line 1433 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2014,7 +2016,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2018 "Python/generated_cases.c.h" + #line 2020 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2022,18 +2024,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1441 "Python/bytecodes.c" + #line 1443 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2031 "Python/generated_cases.c.h" + #line 2033 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1448 "Python/bytecodes.c" + #line 1450 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -2044,22 +2046,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2048 "Python/generated_cases.c.h" + #line 2050 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1461 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2057 "Python/generated_cases.c.h" + #line 2059 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1463 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2063 "Python/generated_cases.c.h" + #line 2065 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2069,10 +2071,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1467 "Python/bytecodes.c" + #line 1469 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2076 "Python/generated_cases.c.h" + #line 2078 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2082,10 +2084,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1472 "Python/bytecodes.c" + #line 1474 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2089 "Python/generated_cases.c.h" + #line 2091 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2095,7 +2097,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1477 "Python/bytecodes.c" + #line 1479 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2106,13 +2108,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2110 "Python/generated_cases.c.h" + #line 2112 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1488 "Python/bytecodes.c" + #line 1490 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2116 "Python/generated_cases.c.h" + #line 2118 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2121,13 +2123,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1495 "Python/bytecodes.c" + #line 1497 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2127 "Python/generated_cases.c.h" + #line 2129 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1497 "Python/bytecodes.c" + #line 1499 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2131 "Python/generated_cases.c.h" + #line 2133 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2135,7 +2137,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1501 "Python/bytecodes.c" + #line 1503 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2150,7 +2152,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2154 "Python/generated_cases.c.h" + #line 2156 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2160,7 +2162,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1518 "Python/bytecodes.c" + #line 1520 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2168,13 +2170,13 @@ if (map == NULL) goto error; - #line 2172 "Python/generated_cases.c.h" + #line 2174 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1526 "Python/bytecodes.c" + #line 1528 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2178 "Python/generated_cases.c.h" + #line 2180 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2182,7 +2184,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1530 "Python/bytecodes.c" + #line 1532 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2222,7 +2224,7 @@ Py_DECREF(ann_dict); } } - #line 2226 "Python/generated_cases.c.h" + #line 2228 "Python/generated_cases.c.h" DISPATCH(); } @@ -2230,7 +2232,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1572 "Python/bytecodes.c" + #line 1574 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2240,14 +2242,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2244 "Python/generated_cases.c.h" + #line 2246 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1582 "Python/bytecodes.c" + #line 1584 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2251 "Python/generated_cases.c.h" + #line 2253 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2255,7 +2257,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1586 "Python/bytecodes.c" + #line 1588 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2263,12 +2265,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2267 "Python/generated_cases.c.h" + #line 2269 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1594 "Python/bytecodes.c" + #line 1596 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2272 "Python/generated_cases.c.h" + #line 2274 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2276,17 +2278,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1600 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2285 "Python/generated_cases.c.h" + #line 2287 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1605 "Python/bytecodes.c" + #line 1607 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2290 "Python/generated_cases.c.h" + #line 2292 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2295,25 +2297,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1611 "Python/bytecodes.c" + #line 1613 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2305 "Python/generated_cases.c.h" + #line 2307 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1619 "Python/bytecodes.c" + #line 1621 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2317 "Python/generated_cases.c.h" + #line 2319 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2324,8 +2326,8 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1633 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + #line 1635 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; @@ -2366,16 +2368,16 @@ } } } - #line 2370 "Python/generated_cases.c.h" + #line 2372 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1675 "Python/bytecodes.c" + #line 1677 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2379 "Python/generated_cases.c.h" + #line 2381 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2390,20 +2392,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1694 "Python/bytecodes.c" + #line 1696 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2401 "Python/generated_cases.c.h" + #line 2403 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1701 "Python/bytecodes.c" + #line 1703 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2407 "Python/generated_cases.c.h" + #line 2409 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2418,12 +2420,12 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1707 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; res2 = _PySuper_Lookup(cls, self, name, @@ -2441,7 +2443,7 @@ res = res2; res2 = NULL; } - #line 2445 "Python/generated_cases.c.h" + #line 2447 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2455,11 +2457,11 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1744 "Python/bytecodes.c" + #line 1746 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -2467,7 +2469,7 @@ STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -2489,9 +2491,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2493 "Python/generated_cases.c.h" + #line 2495 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1778 "Python/bytecodes.c" + #line 1780 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2500,12 +2502,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2504 "Python/generated_cases.c.h" + #line 2506 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1787 "Python/bytecodes.c" + #line 1789 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2509 "Python/generated_cases.c.h" + #line 2511 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2519,7 +2521,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1796 "Python/bytecodes.c" + #line 1798 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2532,7 +2534,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2536 "Python/generated_cases.c.h" + #line 2538 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2547,7 +2549,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1812 "Python/bytecodes.c" + #line 1814 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2560,7 +2562,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2564 "Python/generated_cases.c.h" + #line 2566 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2575,7 +2577,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1828 "Python/bytecodes.c" + #line 1830 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2585,7 +2587,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -2602,7 +2604,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2606 "Python/generated_cases.c.h" + #line 2608 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2617,7 +2619,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1858 "Python/bytecodes.c" + #line 1860 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2627,7 +2629,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2631 "Python/generated_cases.c.h" + #line 2633 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2642,7 +2644,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1871 "Python/bytecodes.c" + #line 1873 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2654,7 +2656,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2658 "Python/generated_cases.c.h" + #line 2660 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2668,7 +2670,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1886 "Python/bytecodes.c" + #line 1888 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2692,7 +2694,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2696 "Python/generated_cases.c.h" + #line 2698 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2700,7 +2702,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1912 "Python/bytecodes.c" + #line 1914 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2714,7 +2716,7 @@ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -2726,7 +2728,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2730 "Python/generated_cases.c.h" + #line 2732 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2734,7 +2736,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1940 "Python/bytecodes.c" + #line 1942 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2752,7 +2754,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2756 "Python/generated_cases.c.h" + #line 2758 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2763,7 +2765,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1960 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2773,7 +2775,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -2802,7 +2804,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2806 "Python/generated_cases.c.h" + #line 2808 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2813,7 +2815,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2001 "Python/bytecodes.c" + #line 2003 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2823,7 +2825,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2827 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2835,7 +2837,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2020 "Python/bytecodes.c" + #line 2022 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2848,12 +2850,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2852 "Python/generated_cases.c.h" + #line 2854 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2033 "Python/bytecodes.c" + #line 2035 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2857 "Python/generated_cases.c.h" + #line 2859 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2864,7 +2866,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2037 "Python/bytecodes.c" + #line 2039 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2875,7 +2877,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2879 "Python/generated_cases.c.h" + #line 2881 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2886,7 +2888,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2051 "Python/bytecodes.c" + #line 2053 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2901,7 +2903,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2905 "Python/generated_cases.c.h" + #line 2907 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2912,7 +2914,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2069 "Python/bytecodes.c" + #line 2071 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2924,7 +2926,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2928 "Python/generated_cases.c.h" + #line 2930 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2935,14 +2937,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2083 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2941 "Python/generated_cases.c.h" + #line 2943 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2085 "Python/bytecodes.c" + #line 2087 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2946 "Python/generated_cases.c.h" + #line 2948 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2952,15 +2954,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2089 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2958 "Python/generated_cases.c.h" + #line 2960 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2091 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2964 "Python/generated_cases.c.h" + #line 2966 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2971,12 +2973,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2096 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2977 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2098 "Python/bytecodes.c" + #line 2100 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2984,10 +2986,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2988 "Python/generated_cases.c.h" + #line 2990 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2106 "Python/bytecodes.c" + #line 2108 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2996,7 +2998,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3000 "Python/generated_cases.c.h" + #line 3002 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3006,21 +3008,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2117 "Python/bytecodes.c" + #line 2119 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3013 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2120 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3020 "Python/generated_cases.c.h" + #line 3022 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2125 "Python/bytecodes.c" + #line 2127 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3024 "Python/generated_cases.c.h" + #line 3026 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3029,15 +3031,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2129 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 2131 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3036 "Python/generated_cases.c.h" + #line 3038 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2132 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3041 "Python/generated_cases.c.h" + #line 3043 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3046,25 +3048,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2136 "Python/bytecodes.c" - PyObject *name = GETITEM(frame->f_code->co_names, oparg); + #line 2138 "Python/bytecodes.c" + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3054 "Python/generated_cases.c.h" + #line 3056 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2142 "Python/bytecodes.c" + #line 2144 "Python/bytecodes.c" JUMPBY(oparg); - #line 3063 "Python/generated_cases.c.h" + #line 3065 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2146 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3081,13 +3083,13 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3085 "Python/generated_cases.c.h" + #line 3087 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2176 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); @@ -3096,20 +3098,20 @@ goto error; } goto resume_frame; - #line 3100 "Python/generated_cases.c.h" + #line 3102 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2187 "Python/bytecodes.c" + #line 2189 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3111 "Python/generated_cases.c.h" + #line 3113 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2193 "Python/bytecodes.c" + #line 2195 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3117,22 +3119,22 @@ if (err < 0) goto pop_1_error; } } - #line 3121 "Python/generated_cases.c.h" + #line 3123 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2203 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3134 "Python/generated_cases.c.h" + #line 3136 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2209 "Python/bytecodes.c" + #line 2211 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3140,63 +3142,63 @@ if (err < 0) goto pop_1_error; } } - #line 3144 "Python/generated_cases.c.h" + #line 3146 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2219 "Python/bytecodes.c" + #line 2221 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3153 "Python/generated_cases.c.h" + #line 3155 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2221 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3158 "Python/generated_cases.c.h" + #line 3160 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2226 "Python/bytecodes.c" + #line 2228 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3170 "Python/generated_cases.c.h" + #line 3172 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2231 "Python/bytecodes.c" + #line 2233 "Python/bytecodes.c" } - #line 3174 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2235 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3187 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2244 "Python/bytecodes.c" + #line 2246 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3200 "Python/generated_cases.c.h" + #line 3202 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3207,16 +3209,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2252 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3216 "Python/generated_cases.c.h" + #line 3218 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2257 "Python/bytecodes.c" + #line 2259 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3224,7 +3226,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3228 "Python/generated_cases.c.h" + #line 3230 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3233,10 +3235,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2267 "Python/bytecodes.c" + #line 2269 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3240 "Python/generated_cases.c.h" + #line 3242 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3245,10 +3247,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2272 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3252 "Python/generated_cases.c.h" + #line 3254 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3258,11 +3260,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2277 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3266 "Python/generated_cases.c.h" + #line 3268 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3271,14 +3273,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2283 "Python/bytecodes.c" + #line 2285 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3278 "Python/generated_cases.c.h" + #line 3280 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2286 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3282 "Python/generated_cases.c.h" + #line 3284 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3286,7 +3288,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2290 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3309,11 +3311,11 @@ if (iter == NULL) { goto error; } - #line 3313 "Python/generated_cases.c.h" + #line 3315 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2313 "Python/bytecodes.c" + #line 2315 "Python/bytecodes.c" } - #line 3317 "Python/generated_cases.c.h" + #line 3319 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3323,7 +3325,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2331 "Python/bytecodes.c" + #line 2333 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3354,7 +3356,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3358 "Python/generated_cases.c.h" + #line 3360 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3362,7 +3364,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2364 "Python/bytecodes.c" + #line 2366 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3388,14 +3390,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3392 "Python/generated_cases.c.h" + #line 3394 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2392 "Python/bytecodes.c" + #line 2394 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3415,7 +3417,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3419 "Python/generated_cases.c.h" + #line 3421 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3425,7 +3427,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2414 "Python/bytecodes.c" + #line 2416 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3445,7 +3447,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3449 "Python/generated_cases.c.h" + #line 3451 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3455,7 +3457,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2436 "Python/bytecodes.c" + #line 2438 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3473,7 +3475,7 @@ if (next == NULL) { goto error; } - #line 3477 "Python/generated_cases.c.h" + #line 3479 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3482,7 +3484,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2456 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3498,14 +3500,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3502 "Python/generated_cases.c.h" + #line 3504 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2474 "Python/bytecodes.c" + #line 2476 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3528,16 +3530,16 @@ Py_DECREF(enter); goto error; } - #line 3532 "Python/generated_cases.c.h" + #line 3534 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2497 "Python/bytecodes.c" + #line 2499 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3541 "Python/generated_cases.c.h" + #line 3543 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3548,7 +3550,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2506 "Python/bytecodes.c" + #line 2508 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3574,16 +3576,16 @@ Py_DECREF(enter); goto error; } - #line 3578 "Python/generated_cases.c.h" + #line 3580 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2532 "Python/bytecodes.c" + #line 2534 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3587 "Python/generated_cases.c.h" + #line 3589 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3595,7 +3597,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2541 "Python/bytecodes.c" + #line 2543 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3616,7 +3618,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3620 "Python/generated_cases.c.h" + #line 3622 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3625,7 +3627,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2580 "Python/bytecodes.c" + #line 2582 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3635,7 +3637,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3639 "Python/generated_cases.c.h" + #line 3641 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3649,7 +3651,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2592 "Python/bytecodes.c" + #line 2594 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3666,7 +3668,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3670 "Python/generated_cases.c.h" + #line 3672 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3680,7 +3682,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2611 "Python/bytecodes.c" + #line 2613 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3690,7 +3692,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3694 "Python/generated_cases.c.h" + #line 3696 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3704,7 +3706,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2623 "Python/bytecodes.c" + #line 2625 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3718,7 +3720,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3722 "Python/generated_cases.c.h" + #line 3724 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3727,16 +3729,16 @@ } TARGET(KW_NAMES) { - #line 2639 "Python/bytecodes.c" + #line 2641 "Python/bytecodes.c" assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); - kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3735 "Python/generated_cases.c.h" + assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); + kwnames = GETITEM(FRAME_CO_CONSTS, oparg); + #line 3737 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2645 "Python/bytecodes.c" + #line 2647 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3749,7 +3751,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3753 "Python/generated_cases.c.h" + #line 3755 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3759,7 +3761,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2690 "Python/bytecodes.c" + #line 2692 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3841,7 +3843,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3845 "Python/generated_cases.c.h" + #line 3847 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3853,7 +3855,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2778 "Python/bytecodes.c" + #line 2780 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3863,7 +3865,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3867 "Python/generated_cases.c.h" + #line 3869 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3872,7 +3874,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2790 "Python/bytecodes.c" + #line 2792 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3898,7 +3900,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3902 "Python/generated_cases.c.h" + #line 3904 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3906,7 +3908,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2818 "Python/bytecodes.c" + #line 2820 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3942,7 +3944,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3946 "Python/generated_cases.c.h" + #line 3948 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3950,7 +3952,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2856 "Python/bytecodes.c" + #line 2858 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3960,7 +3962,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3964 "Python/generated_cases.c.h" + #line 3966 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3973,7 +3975,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2868 "Python/bytecodes.c" + #line 2870 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3984,7 +3986,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3988 "Python/generated_cases.c.h" + #line 3990 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3998,7 +4000,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2882 "Python/bytecodes.c" + #line 2884 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4009,7 +4011,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4013 "Python/generated_cases.c.h" + #line 4015 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4023,7 +4025,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2896 "Python/bytecodes.c" + #line 2898 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4045,7 +4047,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4049 "Python/generated_cases.c.h" + #line 4051 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4059,7 +4061,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2921 "Python/bytecodes.c" + #line 2923 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4087,7 +4089,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4091 "Python/generated_cases.c.h" + #line 4093 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4101,7 +4103,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2952 "Python/bytecodes.c" + #line 2954 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4133,7 +4135,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4137 "Python/generated_cases.c.h" + #line 4139 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4147,7 +4149,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2987 "Python/bytecodes.c" + #line 2989 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4179,7 +4181,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4183 "Python/generated_cases.c.h" + #line 4185 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4193,7 +4195,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3022 "Python/bytecodes.c" + #line 3024 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4218,7 +4220,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4222 "Python/generated_cases.c.h" + #line 4224 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4231,7 +4233,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3049 "Python/bytecodes.c" + #line 3051 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4258,7 +4260,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4262 "Python/generated_cases.c.h" + #line 4264 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4270,7 +4272,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3079 "Python/bytecodes.c" + #line 3081 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4288,14 +4290,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4292 "Python/generated_cases.c.h" + #line 4294 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3099 "Python/bytecodes.c" + #line 3101 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4326,7 +4328,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4330 "Python/generated_cases.c.h" + #line 4332 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4339,7 +4341,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3133 "Python/bytecodes.c" + #line 3135 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4368,7 +4370,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4372 "Python/generated_cases.c.h" + #line 4374 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4381,7 +4383,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3165 "Python/bytecodes.c" + #line 3167 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4410,7 +4412,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4414 "Python/generated_cases.c.h" + #line 4416 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4423,7 +4425,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3197 "Python/bytecodes.c" + #line 3199 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4451,7 +4453,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4455 "Python/generated_cases.c.h" + #line 4457 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4461,9 +4463,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3228 "Python/bytecodes.c" + #line 3230 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4467 "Python/generated_cases.c.h" + #line 4469 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4472,7 +4474,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3232 "Python/bytecodes.c" + #line 3234 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4534,14 +4536,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4538 "Python/generated_cases.c.h" + #line 4540 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3294 "Python/bytecodes.c" + #line 3296 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4545 "Python/generated_cases.c.h" + #line 4547 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4552,7 +4554,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3300 "Python/bytecodes.c" + #line 3302 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4564,7 +4566,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4568 "Python/generated_cases.c.h" + #line 4570 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4572,7 +4574,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3314 "Python/bytecodes.c" + #line 3316 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4597,14 +4599,14 @@ default: Py_UNREACHABLE(); } - #line 4601 "Python/generated_cases.c.h" + #line 4603 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3341 "Python/bytecodes.c" + #line 3343 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4625,7 +4627,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4629 "Python/generated_cases.c.h" + #line 4631 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4633,15 +4635,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3364 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4639 "Python/generated_cases.c.h" + #line 4641 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3366 "Python/bytecodes.c" + #line 3368 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4645 "Python/generated_cases.c.h" + #line 4647 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4652,7 +4654,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3370 "Python/bytecodes.c" + #line 3372 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4687,7 +4689,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4691 "Python/generated_cases.c.h" + #line 4693 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4696,10 +4698,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3407 "Python/bytecodes.c" + #line 3409 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4703 "Python/generated_cases.c.h" + #line 4705 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4711,7 +4713,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3412 "Python/bytecodes.c" + #line 3414 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4726,12 +4728,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4730 "Python/generated_cases.c.h" + #line 4732 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3427 "Python/bytecodes.c" + #line 3429 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4735 "Python/generated_cases.c.h" + #line 4737 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4741,16 +4743,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3432 "Python/bytecodes.c" + #line 3434 "Python/bytecodes.c" assert(oparg >= 2); - #line 4747 "Python/generated_cases.c.h" + #line 4749 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3436 "Python/bytecodes.c" + #line 3438 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4762,26 +4764,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4766 "Python/generated_cases.c.h" + #line 4768 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3450 "Python/bytecodes.c" + #line 3452 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4772 "Python/generated_cases.c.h" + #line 4774 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3454 "Python/bytecodes.c" + #line 3456 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4779 "Python/generated_cases.c.h" + #line 4781 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3459 "Python/bytecodes.c" + #line 3461 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4790,12 +4792,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4794 "Python/generated_cases.c.h" + #line 4796 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3470 "Python/bytecodes.c" + #line 3472 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4804,12 +4806,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4808 "Python/generated_cases.c.h" + #line 4810 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3481 "Python/bytecodes.c" + #line 3483 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4821,12 +4823,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4825 "Python/generated_cases.c.h" + #line 4827 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3495 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4838,30 +4840,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4842 "Python/generated_cases.c.h" + #line 4844 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3509 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4853 "Python/generated_cases.c.h" + #line 4855 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3517 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4860 "Python/generated_cases.c.h" + #line 4862 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3522 "Python/bytecodes.c" + #line 3524 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4867 "Python/generated_cases.c.h" + #line 4869 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 7c0cbdb35e0605..faa5087adebf92 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -855,9 +855,16 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { #endif enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +#define HAS_ARG_FLAG (1) +#define HAS_CONST_FLAG (2) +#define HAS_NAME_FLAG (4) +#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG)) +#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) +#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; + int flags; }; #define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) @@ -868,208 +875,208 @@ struct opcode_metadata { extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { - [NOP] = { true, INSTR_FMT_IX }, - [RESUME] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB }, - [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, - [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, - [LOAD_FAST] = { true, INSTR_FMT_IB }, - [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB }, - [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB }, - [LOAD_CONST] = { true, INSTR_FMT_IB }, - [STORE_FAST] = { true, INSTR_FMT_IB }, - [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB }, - [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB }, - [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB }, - [POP_TOP] = { true, INSTR_FMT_IX }, - [PUSH_NULL] = { true, INSTR_FMT_IX }, - [END_FOR] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX }, - [END_SEND] = { true, INSTR_FMT_IX }, - [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX }, - [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, - [UNARY_NOT] = { true, INSTR_FMT_IX }, - [UNARY_INVERT] = { true, INSTR_FMT_IX }, - [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC }, - [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB }, - [BINARY_SUBSCR] = { true, INSTR_FMT_IXC }, - [BINARY_SLICE] = { true, INSTR_FMT_IX }, - [STORE_SLICE] = { true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, - [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC }, - [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, - [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC }, - [LIST_APPEND] = { true, INSTR_FMT_IB }, - [SET_ADD] = { true, INSTR_FMT_IB }, - [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, - [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, - [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, - [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, - [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, - [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB }, - [RAISE_VARARGS] = { true, INSTR_FMT_IB }, - [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, - [RETURN_VALUE] = { true, INSTR_FMT_IX }, - [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX }, - [RETURN_CONST] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB }, - [GET_AITER] = { true, INSTR_FMT_IX }, - [GET_ANEXT] = { true, INSTR_FMT_IX }, - [GET_AWAITABLE] = { true, INSTR_FMT_IB }, - [SEND] = { true, INSTR_FMT_IBC }, - [SEND_GEN] = { true, INSTR_FMT_IBC }, - [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IX }, - [YIELD_VALUE] = { true, INSTR_FMT_IX }, - [POP_EXCEPT] = { true, INSTR_FMT_IX }, - [RERAISE] = { true, INSTR_FMT_IB }, - [END_ASYNC_FOR] = { true, INSTR_FMT_IX }, - [CLEANUP_THROW] = { true, INSTR_FMT_IX }, - [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX }, - [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX }, - [STORE_NAME] = { true, INSTR_FMT_IB }, - [DELETE_NAME] = { true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC }, - [UNPACK_EX] = { true, INSTR_FMT_IB }, - [STORE_ATTR] = { true, INSTR_FMT_IBC000 }, - [DELETE_ATTR] = { true, INSTR_FMT_IB }, - [STORE_GLOBAL] = { true, INSTR_FMT_IB }, - [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, - [LOAD_LOCALS] = { true, INSTR_FMT_IB }, - [LOAD_NAME] = { true, INSTR_FMT_IB }, - [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, - [DELETE_FAST] = { true, INSTR_FMT_IB }, - [MAKE_CELL] = { true, INSTR_FMT_IB }, - [DELETE_DEREF] = { true, INSTR_FMT_IB }, - [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB }, - [LOAD_DEREF] = { true, INSTR_FMT_IB }, - [STORE_DEREF] = { true, INSTR_FMT_IB }, - [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, - [BUILD_STRING] = { true, INSTR_FMT_IB }, - [BUILD_TUPLE] = { true, INSTR_FMT_IB }, - [BUILD_LIST] = { true, INSTR_FMT_IB }, - [LIST_EXTEND] = { true, INSTR_FMT_IB }, - [SET_UPDATE] = { true, INSTR_FMT_IB }, - [BUILD_SET] = { true, INSTR_FMT_IB }, - [BUILD_MAP] = { true, INSTR_FMT_IB }, - [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX }, - [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB }, - [DICT_UPDATE] = { true, INSTR_FMT_IB }, - [DICT_MERGE] = { true, INSTR_FMT_IB }, - [MAP_ADD] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC }, - [LOAD_SUPER_METHOD] = { true, INSTR_FMT_IBC }, - [LOAD_ZERO_SUPER_METHOD] = { true, INSTR_FMT_IBC }, - [LOAD_ZERO_SUPER_ATTR] = { true, INSTR_FMT_IBC }, - [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC }, - [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC }, - [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_METHOD] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, - [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, - [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, - [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, - [COMPARE_OP] = { true, INSTR_FMT_IBC }, - [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC }, - [COMPARE_OP_INT] = { true, INSTR_FMT_IBC }, - [COMPARE_OP_STR] = { true, INSTR_FMT_IBC }, - [IS_OP] = { true, INSTR_FMT_IB }, - [CONTAINS_OP] = { true, INSTR_FMT_IB }, - [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, - [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX }, - [IMPORT_NAME] = { true, INSTR_FMT_IB }, - [IMPORT_FROM] = { true, INSTR_FMT_IB }, - [JUMP_FORWARD] = { true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { true, INSTR_FMT_IB }, - [JUMP] = { true, INSTR_FMT_IB }, - [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB }, - [ENTER_EXECUTOR] = { true, INSTR_FMT_IB }, - [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, - [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, - [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, - [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, - [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, - [GET_LEN] = { true, INSTR_FMT_IX }, - [MATCH_CLASS] = { true, INSTR_FMT_IB }, - [MATCH_MAPPING] = { true, INSTR_FMT_IX }, - [MATCH_SEQUENCE] = { true, INSTR_FMT_IX }, - [MATCH_KEYS] = { true, INSTR_FMT_IX }, - [GET_ITER] = { true, INSTR_FMT_IX }, - [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, - [FOR_ITER] = { true, INSTR_FMT_IBC }, - [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB }, - [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, - [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, - [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, - [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, - [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, - [BEFORE_WITH] = { true, INSTR_FMT_IX }, - [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, - [SETUP_FINALLY] = { true, INSTR_FMT_IX }, - [SETUP_CLEANUP] = { true, INSTR_FMT_IX }, - [SETUP_WITH] = { true, INSTR_FMT_IX }, - [POP_BLOCK] = { true, INSTR_FMT_IX }, - [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, - [KW_NAMES] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB }, - [CALL] = { true, INSTR_FMT_IBC00 }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, - [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00 }, - [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00 }, - [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00 }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00 }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 }, - [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX }, - [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { true, INSTR_FMT_IX }, - [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB }, - [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, - [BUILD_SLICE] = { true, INSTR_FMT_IB }, - [FORMAT_VALUE] = { true, INSTR_FMT_IB }, - [COPY] = { true, INSTR_FMT_IB }, - [BINARY_OP] = { true, INSTR_FMT_IBC }, - [SWAP] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX }, - [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, - [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, - [EXTENDED_ARG] = { true, INSTR_FMT_IB }, - [CACHE] = { true, INSTR_FMT_IX }, - [RESERVED] = { true, INSTR_FMT_IX }, + [NOP] = { true, INSTR_FMT_IX, 0 }, + [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_TOP] = { true, INSTR_FMT_IX, 0 }, + [PUSH_NULL] = { true, INSTR_FMT_IX, 0 }, + [END_FOR] = { true, INSTR_FMT_IB, 0 }, + [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, 0 }, + [END_SEND] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 }, + [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, 0 }, + [UNARY_NOT] = { true, INSTR_FMT_IX, 0 }, + [UNARY_INVERT] = { true, INSTR_FMT_IX, 0 }, + [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC, 0 }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB, 0 }, + [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, 0 }, + [BINARY_SLICE] = { true, INSTR_FMT_IX, 0 }, + [STORE_SLICE] = { true, INSTR_FMT_IX, 0 }, + [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, 0 }, + [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, 0 }, + [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC, 0 }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC, 0 }, + [LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_SUBSCR] = { true, INSTR_FMT_IXC, 0 }, + [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, 0 }, + [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC, 0 }, + [DELETE_SUBSCR] = { true, INSTR_FMT_IX, 0 }, + [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, 0 }, + [RETURN_VALUE] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, 0 }, + [RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [GET_AITER] = { true, INSTR_FMT_IX, 0 }, + [GET_ANEXT] = { true, INSTR_FMT_IX, 0 }, + [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_EXCEPT] = { true, INSTR_FMT_IX, 0 }, + [RERAISE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IX, 0 }, + [CLEANUP_THROW] = { true, INSTR_FMT_IX, 0 }, + [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX, 0 }, + [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, 0 }, + [STORE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [DELETE_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [UNPACK_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [STORE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [DELETE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_LOCALS] = { true, INSTR_FMT_IB, 0 }, + [LOAD_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, + [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, + [DELETE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BUILD_SET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, 0 }, + [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [DICT_MERGE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [MAP_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_SUPER_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_ZERO_SUPER_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_ZERO_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_METHOD] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, 0 }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, 0 }, + [COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [COMPARE_OP_INT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [COMPARE_OP_STR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CONTAINS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CHECK_EG_MATCH] = { true, INSTR_FMT_IX, 0 }, + [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, 0 }, + [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [GET_LEN] = { true, INSTR_FMT_IX, 0 }, + [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, + [MATCH_SEQUENCE] = { true, INSTR_FMT_IX, 0 }, + [MATCH_KEYS] = { true, INSTR_FMT_IX, 0 }, + [GET_ITER] = { true, INSTR_FMT_IX, 0 }, + [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, 0 }, + [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, 0 }, + [BEFORE_WITH] = { true, INSTR_FMT_IX, 0 }, + [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, 0 }, + [SETUP_FINALLY] = { true, INSTR_FMT_IX, 0 }, + [SETUP_CLEANUP] = { true, INSTR_FMT_IX, 0 }, + [SETUP_WITH] = { true, INSTR_FMT_IX, 0 }, + [POP_BLOCK] = { true, INSTR_FMT_IX, 0 }, + [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [KW_NAMES] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, + [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, + [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IX, 0 }, + [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX, 0 }, + [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [FORMAT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX, 0 }, + [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CACHE] = { true, INSTR_FMT_IX, 0 }, + [RESERVED] = { true, INSTR_FMT_IX, 0 }, }; #endif diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 3a003b3fba2600..8aa500e9e7412a 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -34,6 +34,11 @@ UNUSED = "unused" BITS_PER_CODE_UNIT = 16 +RESERVED_WORDS = { + "co_consts" : "Use FRAME_CO_CONSTS.", + "co_names": "Use FRAME_CO_NAMES.", +} + arg_parser = argparse.ArgumentParser( description="Generate the code for the interpreter switch.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, @@ -223,6 +228,7 @@ def assign(self, dst: StackEffect, src: StackEffect): def cast(self, dst: StackEffect, src: StackEffect) -> str: return f"({dst.type or 'PyObject *'})" if src.type != dst.type else "" +INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME'] @dataclasses.dataclass class Instruction: @@ -244,6 +250,7 @@ class Instruction: output_effects: list[StackEffect] unmoved_names: frozenset[str] instr_fmt: str + flags: int # Set later family: parser.Family | None = None @@ -272,7 +279,17 @@ def __init__(self, inst: parser.InstDef): else: break self.unmoved_names = frozenset(unmoved_names) - if variable_used(inst, "oparg"): + flag_data = { + 'HAS_ARG' : variable_used(inst, "oparg"), + 'HAS_CONST': variable_used(inst, "FRAME_CO_CONSTS"), + 'HAS_NAME' : variable_used(inst, "FRAME_CO_NAMES"), + } + assert set(flag_data.keys()) == set(INSTRUCTION_FLAGS) + self.flags = 0 + for i, name in enumerate(INSTRUCTION_FLAGS): + self.flags |= (1< None: thing: parser.InstDef | parser.Macro | parser.Family | None thing_first_token = psr.peek() while thing := psr.definition(): + if ws := [w for w in RESERVED_WORDS if variable_used(thing, w)]: + self.error(f"'{ws[0]}' is a reserved word. {RESERVED_WORDS[ws[0]]}", thing) + match thing: case parser.InstDef(name=name): if name in self.instrs: @@ -740,7 +763,7 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: return cache, input, output def analyze_macros_and_pseudos(self) -> None: - """Analyze each super- and macro instruction.""" + """Analyze each macro and pseudo instruction.""" self.macro_instrs = {} self.pseudo_instrs = {} for name, macro in self.macros.items(): @@ -754,6 +777,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: sp = initial_sp parts: list[Component | parser.CacheEffect] = [] format = "IB" + flags = 0 cache = "C" for component in components: match component: @@ -769,11 +793,12 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: for _ in range(ce.size): format += cache cache = "0" + flags |= instr.flags case _: typing.assert_never(component) final_sp = sp return MacroInstruction( - macro.name, stack, initial_sp, final_sp, format, macro, parts + macro.name, stack, initial_sp, final_sp, format, flags, macro, parts ) def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction: @@ -782,7 +807,9 @@ def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction: # Make sure the targets have the same fmt fmts = list(set([t.instr_fmt for t in targets])) assert(len(fmts) == 1) - return PseudoInstruction(pseudo.name, fmts[0], targets) + flags_list = list(set([t.flags for t in targets])) + assert(len(flags_list) == 1) + return PseudoInstruction(pseudo.name, targets, fmts[0], flags_list[0]) def analyze_instruction( self, instr: Instruction, stack: list[StackEffect], sp: int @@ -1005,10 +1032,19 @@ def write_metadata(self) -> None: # Write type definitions self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") + for i, flag in enumerate(INSTRUCTION_FLAGS): + self.out.emit(f"#define {flag}{INSTR_FLAG_SUFFIX} ({1 << i})"); + for flag in INSTRUCTION_FLAGS: + flag_name = f"{flag}{INSTR_FLAG_SUFFIX}" + self.out.emit( + f"#define OPCODE_{flag}(OP) " + f"(_PyOpcode_opcode_metadata[(OP)].flags & ({flag_name}))") + self.out.emit("struct opcode_metadata {") with self.out.indent(): self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") + self.out.emit("int flags;") self.out.emit("};") self.out.emit("") self.out.emit("#define OPCODE_METADATA_FMT(OP) " @@ -1049,23 +1085,25 @@ def write_pseudo_instrs(self) -> None: self.out.emit(f" ((OP) == {op}) || \\") self.out.emit(f" 0") - def write_metadata_for_inst(self, instr: Instruction) -> None: - """Write metadata for a single instruction.""" + def emit_metadata_entry(self, name: str, fmt: str, flags: int) -> None: + flags_strs = [f"{name}{INSTR_FLAG_SUFFIX}" + for i, name in enumerate(INSTRUCTION_FLAGS) if (flags & (1< None: + """Write metadata for a single instruction.""" + self.emit_metadata_entry(instr.name, instr.instr_fmt, instr.flags) + def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" - self.out.emit( - f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," - ) + self.emit_metadata_entry(mac.name, mac.instr_fmt, mac.flags) def write_metadata_for_pseudo(self, ps: PseudoInstruction) -> None: """Write metadata for a macro-instruction.""" - self.out.emit( - f" [{ps.name}] = {{ true, {INSTR_FMT_PREFIX}{ps.instr_fmt} }}," - ) + self.emit_metadata_entry(ps.name, ps.instr_fmt, ps.flags) def write_instructions(self) -> None: """Write instructions to output file.""" From 4e80082723b768df124f77d2b73b3ba6b584a735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Tue, 13 Jun 2023 20:44:27 +0000 Subject: [PATCH 019/446] gh-102613: Bump recursion limit to fix running test_pathlib under Coverage (#105744) --- Lib/test/test_pathlib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 1a008e5cea3f00..5963a3d67ff243 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2107,7 +2107,7 @@ def test_glob_long_symlink(self): self.assertEqual(sorted(base.glob('**/*')), [bad_link]) def test_glob_above_recursion_limit(self): - recursion_limit = 40 + recursion_limit = 50 # directory_depth > recursion_limit directory_depth = recursion_limit + 10 base = pathlib.Path(os_helper.TESTFN, 'deep') From 757b402ea1c2c6b925a55a08fd844b065b6e082f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 13 Jun 2023 15:02:19 -0600 Subject: [PATCH 020/446] gh-104812: Run Pending Calls in any Thread (gh-104813) For a while now, pending calls only run in the main thread (in the main interpreter). This PR changes things to allow any thread run a pending call, unless the pending call was explicitly added for the main thread to run. --- Include/cpython/ceval.h | 2 + Include/internal/pycore_ceval.h | 3 +- Include/internal/pycore_ceval_state.h | 38 +- Include/internal/pycore_pystate.h | 8 - Lib/test/support/threading_helper.py | 9 +- Lib/test/test_capi/test_misc.py | 401 +++++++++++++++++- ...-06-02-15-15-41.gh-issue-104812.dfZiG5.rst | 9 + Modules/_queuemodule.c | 3 +- Modules/_testinternalcapi.c | 122 +++++- Modules/_threadmodule.c | 3 +- Modules/signalmodule.c | 6 +- Python/ceval.c | 55 +++ Python/ceval_gil.c | 213 ++++++---- Python/pylifecycle.c | 3 + Python/pystate.c | 3 +- Tools/c-analyzer/cpython/ignored.tsv | 1 + 16 files changed, 761 insertions(+), 118 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index 0fbbee10c2edce..a9616bd6a4f518 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -22,6 +22,8 @@ PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _P PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); +PyAPI_FUNC(int) _PyEval_MakePendingCalls(PyThreadState *); + PyAPI_FUNC(Py_ssize_t) PyUnstable_Eval_RequestCodeExtraIndex(freefunc); // Old name -- remove when this API changes: _Py_DEPRECATED_EXTERNALLY(3.12) static inline Py_ssize_t diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index ca2703781de4b0..9e9b523e7c2222 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -27,7 +27,8 @@ PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp); PyAPI_FUNC(int) _PyEval_AddPendingCall( PyInterpreterState *interp, int (*func)(void *), - void *arg); + void *arg, + int mainthreadonly); PyAPI_FUNC(void) _PyEval_SignalAsyncExc(PyInterpreterState *interp); #ifdef HAVE_FORK extern PyStatus _PyEval_ReInitThreads(PyThreadState *tstate); diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h index 95d1fa16ba40dc..e56e43c6e0c6a7 100644 --- a/Include/internal/pycore_ceval_state.h +++ b/Include/internal/pycore_ceval_state.h @@ -13,6 +13,24 @@ extern "C" { #include "pycore_gil.h" // struct _gil_runtime_state +struct _pending_calls { + int busy; + PyThread_type_lock lock; + /* Request for running pending calls. */ + _Py_atomic_int calls_to_do; + /* Request for looking at the `async_exc` field of the current + thread state. + Guarded by the GIL. */ + int async_exc; +#define NPENDINGCALLS 32 + struct _pending_call { + int (*func)(void *); + void *arg; + } calls[NPENDINGCALLS]; + int first; + int last; +}; + typedef enum { PERF_STATUS_FAILED = -1, // Perf trampoline is in an invalid state PERF_STATUS_NO_INIT = 0, // Perf trampoline is not initialized @@ -49,6 +67,8 @@ struct _ceval_runtime_state { the main thread of the main interpreter can handle signals: see _Py_ThreadCanHandleSignals(). */ _Py_atomic_int signals_pending; + /* Pending calls to be made only on the main thread. */ + struct _pending_calls pending_mainthread; }; #ifdef PY_HAVE_PERF_TRAMPOLINE @@ -62,24 +82,6 @@ struct _ceval_runtime_state { #endif -struct _pending_calls { - int busy; - PyThread_type_lock lock; - /* Request for running pending calls. */ - _Py_atomic_int calls_to_do; - /* Request for looking at the `async_exc` field of the current - thread state. - Guarded by the GIL. */ - int async_exc; -#define NPENDINGCALLS 32 - struct { - int (*func)(void *); - void *arg; - } calls[NPENDINGCALLS]; - int first; - int last; -}; - struct _ceval_state { /* This single variable consolidates all requests to break out of the fast path in the eval loop. */ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index daa40cf4bcd855..43652c4405ec1a 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -60,14 +60,6 @@ _Py_ThreadCanHandleSignals(PyInterpreterState *interp) } -/* Only execute pending calls on the main thread. */ -static inline int -_Py_ThreadCanHandlePendingCalls(void) -{ - return _Py_IsMainThread(); -} - - /* Variable and static inline functions for in-line access to current thread and interpreter state */ diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py index b9973c8bf5c914..7f16050f32b9d1 100644 --- a/Lib/test/support/threading_helper.py +++ b/Lib/test/support/threading_helper.py @@ -115,7 +115,11 @@ def join_thread(thread, timeout=None): @contextlib.contextmanager def start_threads(threads, unlock=None): - import faulthandler + try: + import faulthandler + except ImportError: + # It isn't supported on subinterpreters yet. + faulthandler = None threads = list(threads) started = [] try: @@ -147,7 +151,8 @@ def start_threads(threads, unlock=None): finally: started = [t for t in started if t.is_alive()] if started: - faulthandler.dump_traceback(sys.stdout) + if faulthandler is not None: + faulthandler.dump_traceback(sys.stdout) raise AssertionError('Unable to join %d threads' % len(started)) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 04a0f8f46cd61e..58e1a83da5c146 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2,17 +2,20 @@ # these are all functions _testcapi exports whose name begins with 'test_'. import _thread -from collections import OrderedDict +from collections import OrderedDict, deque import contextlib import importlib.machinery import importlib.util +import json import os import pickle +import queue import random import sys import textwrap import threading import time +import types import unittest import warnings import weakref @@ -36,6 +39,10 @@ import _testsinglephase except ImportError: _testsinglephase = None +try: + import _xxsubinterpreters as _interpreters +except ModuleNotFoundError: + _interpreters = None # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') @@ -47,6 +54,12 @@ def decode_stderr(err): return err.decode('utf-8', 'replace').replace('\r', '') +def requires_subinterpreters(meth): + """Decorator to skip a test if subinterpreters are not supported.""" + return unittest.skipIf(_interpreters is None, + 'subinterpreters required')(meth) + + def testfunction(self): """some doc""" return self @@ -1259,6 +1272,10 @@ def test_pyobject_getitemdata_error(self): class TestPendingCalls(unittest.TestCase): + # See the comment in ceval.c (at the "handle_eval_breaker" label) + # about when pending calls get run. This is especially relevant + # here for creating deterministic tests. + def pendingcalls_submit(self, l, n): def callback(): #this function can be interrupted by thread switching so let's @@ -1341,6 +1358,388 @@ def genf(): yield gen = genf() self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code) + class PendingTask(types.SimpleNamespace): + + _add_pending = _testinternalcapi.pending_threadfunc + + def __init__(self, req, taskid=None, notify_done=None): + self.id = taskid + self.req = req + self.notify_done = notify_done + + self.creator_tid = threading.get_ident() + self.requester_tid = None + self.runner_tid = None + self.result = None + + def run(self): + assert self.result is None + self.runner_tid = threading.get_ident() + self._run() + if self.notify_done is not None: + self.notify_done() + + def _run(self): + self.result = self.req + + def run_in_pending_call(self, worker_tids): + assert self._add_pending is _testinternalcapi.pending_threadfunc + self.requester_tid = threading.get_ident() + def callback(): + assert self.result is None + # It can be tricky to control which thread handles + # the eval breaker, so we take a naive approach to + # make sure. + if threading.get_ident() not in worker_tids: + self._add_pending(callback, ensure_added=True) + return + self.run() + self._add_pending(callback, ensure_added=True) + + def create_thread(self, worker_tids): + return threading.Thread( + target=self.run_in_pending_call, + args=(worker_tids,), + ) + + def wait_for_result(self): + while self.result is None: + time.sleep(0.01) + + def test_subthreads_can_handle_pending_calls(self): + payload = 'Spam spam spam spam. Lovely spam! Wonderful spam!' + + task = self.PendingTask(payload) + def do_the_work(): + tid = threading.get_ident() + t = task.create_thread({tid}) + with threading_helper.start_threads([t]): + task.wait_for_result() + t = threading.Thread(target=do_the_work) + with threading_helper.start_threads([t]): + pass + + self.assertEqual(task.result, payload) + + def test_many_subthreads_can_handle_pending_calls(self): + main_tid = threading.get_ident() + self.assertEqual(threading.main_thread().ident, main_tid) + + # We can't use queue.Queue since it isn't reentrant relative + # to pending calls. + _queue = deque() + _active = deque() + _done_lock = threading.Lock() + def queue_put(task): + _queue.append(task) + _active.append(True) + def queue_get(): + try: + task = _queue.popleft() + except IndexError: + raise queue.Empty + return task + def queue_task_done(): + _active.pop() + if not _active: + try: + _done_lock.release() + except RuntimeError: + assert not _done_lock.locked() + def queue_empty(): + return not _queue + def queue_join(): + _done_lock.acquire() + _done_lock.release() + + tasks = [] + for i in range(20): + task = self.PendingTask( + req=f'request {i}', + taskid=i, + notify_done=queue_task_done, + ) + tasks.append(task) + queue_put(task) + # This will be released once all the tasks have finished. + _done_lock.acquire() + + def add_tasks(worker_tids): + while True: + if done: + return + try: + task = queue_get() + except queue.Empty: + break + task.run_in_pending_call(worker_tids) + + done = False + def run_tasks(): + while not queue_empty(): + if done: + return + time.sleep(0.01) + # Give the worker a chance to handle any remaining pending calls. + while not done: + time.sleep(0.01) + + # Start the workers and wait for them to finish. + worker_threads = [threading.Thread(target=run_tasks) + for _ in range(3)] + with threading_helper.start_threads(worker_threads): + try: + # Add a pending call for each task. + worker_tids = [t.ident for t in worker_threads] + threads = [threading.Thread(target=add_tasks, args=(worker_tids,)) + for _ in range(3)] + with threading_helper.start_threads(threads): + try: + pass + except BaseException: + done = True + raise # re-raise + # Wait for the pending calls to finish. + queue_join() + # Notify the workers that they can stop. + done = True + except BaseException: + done = True + raise # re-raise + runner_tids = [t.runner_tid for t in tasks] + + self.assertNotIn(main_tid, runner_tids) + for task in tasks: + with self.subTest(f'task {task.id}'): + self.assertNotEqual(task.requester_tid, main_tid) + self.assertNotEqual(task.requester_tid, task.runner_tid) + self.assertNotIn(task.requester_tid, runner_tids) + + @requires_subinterpreters + def test_isolated_subinterpreter(self): + # We exercise the most important permutations. + + # This test relies on pending calls getting called + # (eval breaker tripped) at each loop iteration + # and at each call. + + maxtext = 250 + main_interpid = 0 + interpid = _interpreters.create() + _interpreters.run_string(interpid, f"""if True: + import json + import os + import threading + import time + import _testinternalcapi + from test.support import threading_helper + """) + + def create_pipe(): + r, w = os.pipe() + self.addCleanup(lambda: os.close(r)) + self.addCleanup(lambda: os.close(w)) + return r, w + + with self.subTest('add in main, run in subinterpreter'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + global done, waiting + waiting = True + os_read({r_done}, 1) + done = True + t = threading.Thread(target=wait) + with threading_helper.start_threads([t]): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + """) + t = threading.Thread(target=do_work) + with threading_helper.start_threads([t]): + os.read(r_ready, 1) + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify(interpid) + # Signal the subinterpreter to stop. + os.write(w_done, b'\0') + + self.assertEqual(actual, int(interpid)) + + with self.subTest('add in main, run in subinterpreter sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + waiting = False + done = False + def subthread(): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + t = threading.Thread(target=subthread) + with threading_helper.start_threads([t]): + # Wait until this interp has handled the pending call. + waiting = True + os.read({r_done}, 1) + done = True + """) + t = threading.Thread(target=do_work) + with threading_helper.start_threads([t]): + os.read(r_ready, 1) + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify(interpid) + # Signal the subinterpreter to stop. + os.write(w_done, b'\0') + + self.assertEqual(actual, int(interpid)) + + with self.subTest('add in subinterpreter, run in main'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def add_job(): + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({main_interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + nonlocal done, waiting + waiting = True + os_read(r_done, 1) + done = True + t1 = threading.Thread(target=add_job) + t2 = threading.Thread(target=wait) + with threading_helper.start_threads([t1, t2]): + while not waiting: + pass + os.write(w_ready, b'\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > timeout: + raise Exception('timed out!') + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(main_interpid)) + + with self.subTest('add in subinterpreter, run in sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def add_job(): + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({main_interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + # Wait until this interp has handled the pending call. + waiting = False + done = False + def wait(os_read=os.read): + nonlocal done, waiting + waiting = True + os_read(r_done, 1) + done = True + def subthread(): + while not waiting: + pass + os.write(w_ready, b'\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > timeout: + raise Exception('timed out!') + t1 = threading.Thread(target=add_job) + t2 = threading.Thread(target=wait) + t3 = threading.Thread(target=subthread) + with threading_helper.start_threads([t1, t2, t3]): + pass + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(main_interpid)) + + # XXX We can't use the rest until gh-105716 is fixed. + return + + with self.subTest('add in subinterpreter, run in subinterpreter sub-thread'): + r_ready, w_ready = create_pipe() + r_done, w_done= create_pipe() + r_data, w_data= create_pipe() + timeout = time.time() + 30 # seconds + + def do_work(): + _interpreters.run_string(interpid, f"""if True: + waiting = False + done = False + def subthread(): + while not waiting: + pass + os.write({w_ready}, b'\\0') + # Loop to trigger the eval breaker. + while not done: + time.sleep(0.01) + if time.time() > {timeout}: + raise Exception('timed out!') + t = threading.Thread(target=subthread) + with threading_helper.start_threads([t]): + # Wait until this interp has handled the pending call. + waiting = True + os.read({r_done}, 1) + done = True + """) + t = threading.Thread(target=do_work) + #with threading_helper.start_threads([t]): + t.start() + if True: + os.read(r_ready, 1) + _interpreters.run_string(interpid, f"""if True: + # Add the pending call and wait for it to finish. + actual = _testinternalcapi.pending_identify({interpid}) + # Signal the subinterpreter to stop. + os.write({w_done}, b'\\0') + os.write({w_data}, actual.to_bytes(1, 'little')) + """) + t.join() + text = os.read(r_data, 1) + actual = int.from_bytes(text, 'little') + + self.assertEqual(actual, int(interpid)) + class SubinterpreterTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst new file mode 100644 index 00000000000000..da29a8cae61839 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-15-15-41.gh-issue-104812.dfZiG5.rst @@ -0,0 +1,9 @@ +The "pending call" machinery now works for all interpreters, not just the +main interpreter, and runs in all threads, not just the main thread. Some +calls are still only done in the main thread, ergo in the main interpreter. +This change does not affect signal handling nor the existing public C-API +(``Py_AddPendingCall()``), which both still only target the main thread. +The new functionality is meant strictly for internal use for now, since +consequences of its use are not well understood yet outside some very +restricted cases. This change brings the capability in line with the +intention when the state was made per-interpreter several years ago. diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index d36a911a57c02c..db5be842b8a35c 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -210,6 +210,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, PyObject *item; PyLockStatus r; PY_TIMEOUT_T microseconds; + PyThreadState *tstate = PyThreadState_Get(); if (block == 0) { /* Non-blocking */ @@ -253,7 +254,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls, Py_END_ALLOW_THREADS } - if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) { + if (r == PY_LOCK_INTR && _PyEval_MakePendingCalls(tstate) < 0) { return NULL; } if (r == PY_LOCK_FAILURE) { diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b43dc7fbf3236c..3de32a32750ebc 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -13,16 +13,18 @@ #include "Python.h" #include "frameobject.h" +#include "interpreteridobject.h" // _PyInterpreterID_LookUp() #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble +#include "pycore_ceval.h" // _PyEval_AddPendingCall #include "pycore_fileutils.h" // _Py_normpath #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_gc.h" // PyGC_Head #include "pycore_hashtable.h" // _Py_hashtable_new() #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() -#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy() +#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() #include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost() #include "pycore_pystate.h" // _PyThreadState_GET() #include "osdefs.h" // MAXPATHLEN @@ -838,6 +840,120 @@ set_optimizer(PyObject *self, PyObject *opt) Py_RETURN_NONE; } + +static int _pending_callback(void *arg) +{ + /* we assume the argument is callable object to which we own a reference */ + PyObject *callable = (PyObject *)arg; + PyObject *r = PyObject_CallNoArgs(callable); + Py_DECREF(callable); + Py_XDECREF(r); + return r != NULL ? 0 : -1; +} + +/* The following requests n callbacks to _pending_callback. It can be + * run from any python thread. + */ +static PyObject * +pending_threadfunc(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *callable; + int ensure_added = 0; + static char *kwlist[] = {"", "ensure_added", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|$p:pending_threadfunc", kwlist, + &callable, &ensure_added)) + { + return NULL; + } + PyInterpreterState *interp = PyInterpreterState_Get(); + + /* create the reference for the callbackwhile we hold the lock */ + Py_INCREF(callable); + + int r; + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, &_pending_callback, callable, 0); + Py_END_ALLOW_THREADS + if (r < 0) { + /* unsuccessful add */ + if (!ensure_added) { + Py_DECREF(callable); + Py_RETURN_FALSE; + } + do { + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, &_pending_callback, callable, 0); + Py_END_ALLOW_THREADS + } while (r < 0); + } + + Py_RETURN_TRUE; +} + + +static struct { + int64_t interpid; +} pending_identify_result; + +static int +_pending_identify_callback(void *arg) +{ + PyThread_type_lock mutex = (PyThread_type_lock)arg; + assert(pending_identify_result.interpid == -1); + PyThreadState *tstate = PyThreadState_Get(); + pending_identify_result.interpid = PyInterpreterState_GetID(tstate->interp); + PyThread_release_lock(mutex); + return 0; +} + +static PyObject * +pending_identify(PyObject *self, PyObject *args) +{ + PyObject *interpid; + if (!PyArg_ParseTuple(args, "O:pending_identify", &interpid)) { + return NULL; + } + PyInterpreterState *interp = _PyInterpreterID_LookUp(interpid); + if (interp == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, "interpreter not found"); + } + return NULL; + } + + pending_identify_result.interpid = -1; + + PyThread_type_lock mutex = PyThread_allocate_lock(); + if (mutex == NULL) { + return NULL; + } + PyThread_acquire_lock(mutex, WAIT_LOCK); + /* It gets released in _pending_identify_callback(). */ + + int r; + do { + Py_BEGIN_ALLOW_THREADS + r = _PyEval_AddPendingCall(interp, + &_pending_identify_callback, (void *)mutex, + 0); + Py_END_ALLOW_THREADS + } while (r < 0); + + /* Wait for the pending call to complete. */ + PyThread_acquire_lock(mutex, WAIT_LOCK); + PyThread_release_lock(mutex); + PyThread_free_lock(mutex); + + PyObject *res = PyLong_FromLongLong(pending_identify_result.interpid); + pending_identify_result.interpid = -1; + if (res == NULL) { + return NULL; + } + return res; +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -868,6 +984,10 @@ static PyMethodDef module_functions[] = { {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"get_counter_optimizer", get_counter_optimizer, METH_NOARGS, NULL}, + {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), + METH_VARARGS | METH_KEYWORDS}, +// {"pending_fd_identify", pending_fd_identify, METH_VARARGS, NULL}, + {"pending_identify", pending_identify, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index b6f878e07526db..c553d039462af0 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -81,6 +81,7 @@ lock_dealloc(lockobject *self) static PyLockStatus acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) { + PyThreadState *tstate = _PyThreadState_GET(); _PyTime_t endtime = 0; if (timeout > 0) { endtime = _PyDeadline_Init(timeout); @@ -103,7 +104,7 @@ acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) /* Run signal handlers if we were interrupted. Propagate * exceptions from signal handlers, such as KeyboardInterrupt, by * passing up PY_LOCK_INTR. */ - if (Py_MakePendingCalls() < 0) { + if (_PyEval_MakePendingCalls(tstate) < 0) { return PY_LOCK_INTR; } diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 2350236ad46b25..00ea4343735dab 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -314,7 +314,8 @@ trip_signal(int sig_num) still use it for this exceptional case. */ _PyEval_AddPendingCall(interp, report_wakeup_send_error, - (void *)(intptr_t) last_error); + (void *)(intptr_t) last_error, + 1); } } } @@ -333,7 +334,8 @@ trip_signal(int sig_num) still use it for this exceptional case. */ _PyEval_AddPendingCall(interp, report_wakeup_write_error, - (void *)(intptr_t)errno); + (void *)(intptr_t)errno, + 1); } } } diff --git a/Python/ceval.c b/Python/ceval.c index e81b6beedfcee1..b91f94d2873963 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -758,6 +758,61 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int * We need to do reasonably frequently, but not too frequently. * All loops should include a check of the eval breaker. * We also check on return from any builtin function. + * + * ## More Details ### + * + * The eval loop (this function) normally executes the instructions + * of a code object sequentially. However, the runtime supports a + * number of out-of-band execution scenarios that may pause that + * sequential execution long enough to do that out-of-band work + * in the current thread using the current PyThreadState. + * + * The scenarios include: + * + * - cyclic garbage collection + * - GIL drop requests + * - "async" exceptions + * - "pending calls" (some only in the main thread) + * - signal handling (only in the main thread) + * + * When the need for one of the above is detected, the eval loop + * pauses long enough to handle the detected case. Then, if doing + * so didn't trigger an exception, the eval loop resumes executing + * the sequential instructions. + * + * To make this work, the eval loop periodically checks if any + * of the above needs to happen. The individual checks can be + * expensive if computed each time, so a while back we switched + * to using pre-computed, per-interpreter variables for the checks, + * and later consolidated that to a single "eval breaker" variable + * (now a PyInterpreterState field). + * + * For the longest time, the eval breaker check would happen + * frequently, every 5 or so times through the loop, regardless + * of what instruction ran last or what would run next. Then, in + * early 2021 (gh-18334, commit 4958f5d), we switched to checking + * the eval breaker less frequently, by hard-coding the check to + * specific places in the eval loop (e.g. certain instructions). + * The intent then was to check after returning from calls + * and on the back edges of loops. + * + * In addition to being more efficient, that approach keeps + * the eval loop from running arbitrary code between instructions + * that don't handle that well. (See gh-74174.) + * + * Currently, the eval breaker check happens here at the + * "handle_eval_breaker" label. Some instructions come here + * explicitly (goto) and some indirectly. Notably, the check + * happens on back edges in the control flow graph, which + * pretty much applies to all loops and most calls. + * (See bytecodes.c for exact information.) + * + * One consequence of this approach is that it might not be obvious + * how to force any specific thread to pick up the eval breaker, + * or for any specific thread to not pick it up. Mostly this + * involves judicious uses of locks and careful ordering of code, + * while avoiding code that might trigger the eval breaker + * until so desired. */ if (_Py_HandlePending(tstate) != 0) { goto error; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 723cf0f4df94d0..bb1279f46cf9f7 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -68,8 +68,9 @@ COMPUTE_EVAL_BREAKER(PyInterpreterState *interp, _Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request) | (_Py_atomic_load_relaxed_int32(&ceval->signals_pending) && _Py_ThreadCanHandleSignals(interp)) - | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do) - && _Py_ThreadCanHandlePendingCalls()) + | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)) + | (_Py_IsMainThread() && _Py_IsMainInterpreter(interp) + &&_Py_atomic_load_relaxed_int32(&ceval->pending_mainthread.calls_to_do)) | ceval2->pending.async_exc | _Py_atomic_load_relaxed_int32(&ceval2->gc_scheduled)); } @@ -95,11 +96,11 @@ RESET_GIL_DROP_REQUEST(PyInterpreterState *interp) static inline void -SIGNAL_PENDING_CALLS(PyInterpreterState *interp) +SIGNAL_PENDING_CALLS(struct _pending_calls *pending, PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; - _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1); + _Py_atomic_store_relaxed(&pending->calls_to_do, 1); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } @@ -109,6 +110,9 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp) { struct _ceval_runtime_state *ceval = &interp->runtime->ceval; struct _ceval_state *ceval2 = &interp->ceval; + if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { + _Py_atomic_store_relaxed(&ceval->pending_mainthread.calls_to_do, 0); + } _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0); COMPUTE_EVAL_BREAKER(interp, ceval, ceval2); } @@ -803,19 +807,31 @@ _push_pending_call(struct _pending_calls *pending, return 0; } -/* Pop one item off the queue while holding the lock. */ -static void -_pop_pending_call(struct _pending_calls *pending, - int (**func)(void *), void **arg) +static int +_next_pending_call(struct _pending_calls *pending, + int (**func)(void *), void **arg) { int i = pending->first; if (i == pending->last) { - return; /* Queue empty */ + /* Queue empty */ + assert(pending->calls[i].func == NULL); + return -1; } - *func = pending->calls[i].func; *arg = pending->calls[i].arg; - pending->first = (i + 1) % NPENDINGCALLS; + return i; +} + +/* Pop one item off the queue while holding the lock. */ +static void +_pop_pending_call(struct _pending_calls *pending, + int (**func)(void *), void **arg) +{ + int i = _next_pending_call(pending, func, arg); + if (i >= 0) { + pending->calls[i] = (struct _pending_call){0}; + pending->first = (i + 1) % NPENDINGCALLS; + } } /* This implementation is thread-safe. It allows @@ -825,9 +841,16 @@ _pop_pending_call(struct _pending_calls *pending, int _PyEval_AddPendingCall(PyInterpreterState *interp, - int (*func)(void *), void *arg) + int (*func)(void *), void *arg, + int mainthreadonly) { + assert(!mainthreadonly || _Py_IsMainInterpreter(interp)); struct _pending_calls *pending = &interp->ceval.pending; + if (mainthreadonly) { + /* The main thread only exists in the main interpreter. */ + assert(_Py_IsMainInterpreter(interp)); + pending = &_PyRuntime.ceval.pending_mainthread; + } /* Ensure that _PyEval_InitState() was called and that _PyEval_FiniState() is not called yet. */ assert(pending->lock != NULL); @@ -837,39 +860,17 @@ _PyEval_AddPendingCall(PyInterpreterState *interp, PyThread_release_lock(pending->lock); /* signal main loop */ - SIGNAL_PENDING_CALLS(interp); + SIGNAL_PENDING_CALLS(pending, interp); return result; } int Py_AddPendingCall(int (*func)(void *), void *arg) { - /* Best-effort to support subinterpreters and calls with the GIL released. - - First attempt _PyThreadState_GET() since it supports subinterpreters. - - If the GIL is released, _PyThreadState_GET() returns NULL . In this - case, use PyGILState_GetThisThreadState() which works even if the GIL - is released. - - Sadly, PyGILState_GetThisThreadState() doesn't support subinterpreters: - see bpo-10915 and bpo-15751. - - Py_AddPendingCall() doesn't require the caller to hold the GIL. */ - PyThreadState *tstate = _PyThreadState_GET(); - if (tstate == NULL) { - tstate = PyGILState_GetThisThreadState(); - } - - PyInterpreterState *interp; - if (tstate != NULL) { - interp = tstate->interp; - } - else { - /* Last resort: use the main interpreter */ - interp = _PyInterpreterState_Main(); - } - return _PyEval_AddPendingCall(interp, func, arg); + /* Legacy users of this API will continue to target the main thread + (of the main interpreter). */ + PyInterpreterState *interp = _PyInterpreterState_Main(); + return _PyEval_AddPendingCall(interp, func, arg, 1); } static int @@ -889,27 +890,24 @@ handle_signals(PyThreadState *tstate) return 0; } -static int -make_pending_calls(PyInterpreterState *interp) +static inline int +maybe_has_pending_calls(PyInterpreterState *interp) { - /* only execute pending calls on main thread */ - if (!_Py_ThreadCanHandlePendingCalls()) { - return 0; + struct _pending_calls *pending = &interp->ceval.pending; + if (_Py_atomic_load_relaxed_int32(&pending->calls_to_do)) { + return 1; } - - /* don't perform recursive pending calls */ - if (interp->ceval.pending.busy) { + if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(interp)) { return 0; } - interp->ceval.pending.busy = 1; - - /* unsignal before starting to call callbacks, so that any callback - added in-between re-signals */ - UNSIGNAL_PENDING_CALLS(interp); - int res = 0; + pending = &_PyRuntime.ceval.pending_mainthread; + return _Py_atomic_load_relaxed_int32(&pending->calls_to_do); +} +static int +_make_pending_calls(struct _pending_calls *pending) +{ /* perform a bounded number of calls, in case of recursion */ - struct _pending_calls *pending = &interp->ceval.pending; for (int i=0; iceval.pending; + struct _pending_calls *pending_main = &_PyRuntime.ceval.pending_mainthread; + + /* Only one thread (per interpreter) may run the pending calls + at once. In the same way, we don't do recursive pending calls. */ + PyThread_acquire_lock(pending->lock, WAIT_LOCK); + if (pending->busy) { + /* A pending call was added after another thread was already + handling the pending calls (and had already "unsignaled"). + Once that thread is done, it may have taken care of all the + pending calls, or there might be some still waiting. + Regardless, this interpreter's pending calls will stay + "signaled" until that first thread has finished. At that + point the next thread to trip the eval breaker will take + care of any remaining pending calls. Until then, though, + all the interpreter's threads will be tripping the eval + breaker every time it's checked. */ + PyThread_release_lock(pending->lock); + return 0; + } + pending->busy = 1; + PyThread_release_lock(pending->lock); + + /* unsignal before starting to call callbacks, so that any callback + added in-between re-signals */ + UNSIGNAL_PENDING_CALLS(interp); + + if (_make_pending_calls(pending) != 0) { + pending->busy = 0; + /* There might not be more calls to make, but we play it safe. */ + SIGNAL_PENDING_CALLS(pending, interp); + return -1; + } - interp->ceval.pending.busy = 0; - return res; + if (_Py_IsMainThread() && _Py_IsMainInterpreter(interp)) { + if (_make_pending_calls(pending_main) != 0) { + pending->busy = 0; + /* There might not be more calls to make, but we play it safe. */ + SIGNAL_PENDING_CALLS(pending_main, interp); + return -1; + } + } -error: - interp->ceval.pending.busy = 0; - SIGNAL_PENDING_CALLS(interp); - return res; + pending->busy = 0; + return 0; } void @@ -944,12 +984,6 @@ _Py_FinishPendingCalls(PyThreadState *tstate) assert(PyGILState_Check()); assert(is_tstate_valid(tstate)); - struct _pending_calls *pending = &tstate->interp->ceval.pending; - - if (!_Py_atomic_load_relaxed_int32(&(pending->calls_to_do))) { - return; - } - if (make_pending_calls(tstate->interp) < 0) { PyObject *exc = _PyErr_GetRaisedException(tstate); PyErr_BadInternalCall(); @@ -958,6 +992,29 @@ _Py_FinishPendingCalls(PyThreadState *tstate) } } +int +_PyEval_MakePendingCalls(PyThreadState *tstate) +{ + int res; + + if (_Py_IsMainThread() && _Py_IsMainInterpreter(tstate->interp)) { + /* Python signal handler doesn't really queue a callback: + it only signals that a signal was received, + see _PyEval_SignalReceived(). */ + res = handle_signals(tstate); + if (res != 0) { + return res; + } + } + + res = make_pending_calls(tstate->interp); + if (res != 0) { + return res; + } + + return 0; +} + /* Py_MakePendingCalls() is a simple wrapper for the sake of backward-compatibility. */ int @@ -968,19 +1025,11 @@ Py_MakePendingCalls(void) PyThreadState *tstate = _PyThreadState_GET(); assert(is_tstate_valid(tstate)); - /* Python signal handler doesn't really queue a callback: it only signals - that a signal was received, see _PyEval_SignalReceived(). */ - int res = handle_signals(tstate); - if (res != 0) { - return res; - } - - res = make_pending_calls(tstate->interp); - if (res != 0) { - return res; + /* Only execute pending calls on the main thread. */ + if (!_Py_IsMainThread() || !_Py_IsMainInterpreter(tstate->interp)) { + return 0; } - - return 0; + return _PyEval_MakePendingCalls(tstate); } void @@ -1020,7 +1069,7 @@ _Py_HandlePending(PyThreadState *tstate) } /* Pending calls */ - if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->pending.calls_to_do)) { + if (maybe_has_pending_calls(tstate->interp)) { if (make_pending_calls(tstate->interp) != 0) { return -1; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 9ae03d4d783117..d45b739c279737 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2152,6 +2152,9 @@ Py_EndInterpreter(PyThreadState *tstate) // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate); + // Make any remaining pending calls. + _Py_FinishPendingCalls(tstate); + _PyAtExit_Call(tstate->interp); if (tstate != interp->threads.head || tstate->next != NULL) { diff --git a/Python/pystate.c b/Python/pystate.c index fb95825ae09776..52d6b29d78605a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -380,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime); _Py_COMP_DIAG_POP -#define NUMLOCKS 8 +#define NUMLOCKS 9 #define LOCKS_INIT(runtime) \ { \ &(runtime)->interpreters.mutex, \ @@ -388,6 +388,7 @@ _Py_COMP_DIAG_POP &(runtime)->getargs.mutex, \ &(runtime)->unicode_state.ids.lock, \ &(runtime)->imports.extensions.mutex, \ + &(runtime)->ceval.pending_mainthread.lock, \ &(runtime)->atexit.mutex, \ &(runtime)->audit_hooks.mutex, \ &(runtime)->allocators.mutex, \ diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 607976f5afdc68..87d9b39c16113b 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -517,6 +517,7 @@ Modules/_testcapimodule.c - g_type_watchers_installed - Modules/_testimportmultiple.c - _barmodule - Modules/_testimportmultiple.c - _foomodule - Modules/_testimportmultiple.c - _testimportmultiple - +Modules/_testinternalcapi.c - pending_identify_result - Modules/_testmultiphase.c - Example_Type_slots - Modules/_testmultiphase.c - Example_Type_spec - Modules/_testmultiphase.c - Example_methods - From 457a459c7804950d4c27a243b176eb933ec87a06 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 00:32:12 +0200 Subject: [PATCH 021/446] gh-98040: Fix importbench: use types.ModuleType() (#105743) Replace removed imp.new_module(name) with types.ModuleType(name). --- Doc/whatsnew/3.12.rst | 2 ++ Tools/importbench/importbench.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bfbc6c7a35c6ff..1e063ed7d2263d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1369,6 +1369,8 @@ Removed * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) + * Replace ``imp.new_module(name)`` with ``types.ModuleType(name)``. + * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint `_. diff --git a/Tools/importbench/importbench.py b/Tools/importbench/importbench.py index 619263b553c081..0c4b3bc73517c5 100644 --- a/Tools/importbench/importbench.py +++ b/Tools/importbench/importbench.py @@ -15,6 +15,7 @@ import sys import tabnanny import timeit +import types def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): @@ -40,7 +41,7 @@ def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): def from_cache(seconds, repeat): """sys.modules""" name = '' - module = imp.new_module(name) + module = types.ModuleType(name) module.__file__ = '' module.__package__ = '' with util.uncache(name): From 4cefe3cf10f498c0927ae4fdba4880d5a64826e4 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 14 Jun 2023 00:00:16 +0100 Subject: [PATCH 022/446] gh-105436: Ignore unrelated errors when checking empty env (GH-105742) --- Lib/test/test_subprocess.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 3d4fffbb8e794a..817eab0c8a7e19 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1695,9 +1695,10 @@ def test_run_with_pathlike_path_and_arguments(self): @unittest.skipUnless(mswindows, "Maybe test trigger a leak on Ubuntu") def test_run_with_an_empty_env(self): # gh-105436: fix subprocess.run(..., env={}) broken on Windows - args = [sys.executable, "-c", 'import sys; sys.exit(57)'] - res = subprocess.run(args, env={}) - self.assertEqual(res.returncode, 57) + args = [sys.executable, "-c", 'pass'] + # Ignore subprocess errors - we only care that the API doesn't + # raise an OSError + subprocess.run(args, env={}) def test_capture_output(self): cp = self.run_python(("import sys;" From f3266c05b6186ab6d1db0799c06b8f76aefe7cf1 Mon Sep 17 00:00:00 2001 From: zentarim <33746047+zentarim@users.noreply.github.com> Date: Wed, 14 Jun 2023 02:45:47 +0300 Subject: [PATCH 023/446] GH-104554: Add RTSPS support to `urllib/parse.py` (#104605) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * GH-104554: Add RTSPS support to `urllib/parse.py` RTSPS is the permanent scheme defined in https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml alongside RTSP and RTSPU schemes. * 📜🤖 Added by blurb_it. --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- Doc/library/urllib.parse.rst | 6 +++--- Lib/urllib/parse.py | 10 +++++----- .../2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 5a9a53f83dace0..e1aa4ebb0964dd 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -23,9 +23,9 @@ to an absolute URL given a "base URL." The module has been designed to match the internet RFC on Relative Uniform Resource Locators. It supports the following URL schemes: ``file``, ``ftp``, ``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``mailto``, ``mms``, -``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtspu``, ``sftp``, -``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, ``telnet``, -``wais``, ``ws``, ``wss``. +``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtsps``, ``rtspu``, +``sftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, +``telnet``, ``wais``, ``ws``, ``wss``. The :mod:`urllib.parse` module defines functions that fall into two broad categories: URL parsing and URL quoting. These are covered in detail in diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index b73b34428764f7..c129b0d7971d71 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -52,18 +52,18 @@ uses_relative = ['', 'ftp', 'http', 'gopher', 'nntp', 'imap', 'wais', 'file', 'https', 'shttp', 'mms', - 'prospero', 'rtsp', 'rtspu', 'sftp', + 'prospero', 'rtsp', 'rtsps', 'rtspu', 'sftp', 'svn', 'svn+ssh', 'ws', 'wss'] uses_netloc = ['', 'ftp', 'http', 'gopher', 'nntp', 'telnet', 'imap', 'wais', 'file', 'mms', 'https', 'shttp', - 'snews', 'prospero', 'rtsp', 'rtspu', 'rsync', + 'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync', 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh', 'ws', 'wss', 'itms-services'] uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap', - 'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips', - 'mms', 'sftp', 'tel'] + 'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip', + 'sips', 'mms', 'sftp', 'tel'] # These are not actually used anymore, but should stay for backwards # compatibility. (They are undocumented, but have a public-looking name.) @@ -72,7 +72,7 @@ 'telnet', 'wais', 'imap', 'snews', 'sip', 'sips'] uses_query = ['', 'http', 'wais', 'imap', 'https', 'shttp', 'mms', - 'gopher', 'rtsp', 'rtspu', 'sip', 'sips'] + 'gopher', 'rtsp', 'rtsps', 'rtspu', 'sip', 'sips'] uses_fragment = ['', 'ftp', 'hdl', 'http', 'gopher', 'news', 'nntp', 'wais', 'https', 'shttp', 'snews', diff --git a/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst b/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst new file mode 100644 index 00000000000000..9ef8c67459c406 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-05-14-43-56.gh-issue-104554.pwfKIo.rst @@ -0,0 +1 @@ +Add RTSPS scheme support in urllib.parse From b542972dc133973a7f0517aa1b61779271789111 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 02:33:00 +0200 Subject: [PATCH 024/446] gh-105387: Limited C API implements Py_INCREF() as func (#105388) In the limited C API version 3.12, Py_INCREF() and Py_DECREF() functions are now implemented as opaque function calls to hide implementation details. --- Doc/whatsnew/3.12.rst | 5 +++++ Include/object.h | 18 ++++++++++-------- ...3-06-09-12-35-55.gh-issue-105387.wM_oL-.rst | 3 +++ 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1e063ed7d2263d..8febb6cc86b6fe 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1694,6 +1694,11 @@ New Features (Contributed by Eddie Elizondo in :gh:`84436`.) +* In the limited C API version 3.12, :c:func:`Py_INCREF` and + :c:func:`Py_DECREF` functions are now implemented as opaque function calls to + hide implementation details. + (Contributed by Victor Stinner in :gh:`105387`.) + Porting to Python 3.12 ---------------------- diff --git a/Include/object.h b/Include/object.h index ad16b72cd42474..3ef64511399c66 100644 --- a/Include/object.h +++ b/Include/object.h @@ -610,10 +610,11 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) { -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) - // Stable ABI for Python built in debug mode. _Py_IncRef() was added to - // Python 3.10.0a7, use Py_IncRef() on older Python versions. Py_IncRef() - // accepts NULL whereas _Py_IncRef() doesn't. +#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) + // Stable ABI implements Py_INCREF() as a function call on limited C API + // version 3.12 and newer, and on Python built in debug mode. _Py_IncRef() + // was added to Python 3.10.0a7, use Py_IncRef() on older Python versions. + // Py_IncRef() accepts NULL whereas _Py_IncRef() doesn't. # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_IncRef(op); # else @@ -647,10 +648,11 @@ static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op) # define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op)) #endif -#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) -// Stable ABI for Python built in debug mode. _Py_DecRef() was added to Python -// 3.10.0a7, use Py_DecRef() on older Python versions. Py_DecRef() accepts NULL -// whereas _Py_IncRef() doesn't. +#if defined(Py_LIMITED_API) && (Py_LIMITED_API+0 >= 0x030c0000 || defined(Py_REF_DEBUG)) +// Stable ABI implements Py_DECREF() as a function call on limited C API +// version 3.12 and newer, and on Python built in debug mode. _Py_DecRef() was +// added to Python 3.10.0a7, use Py_DecRef() on older Python versions. +// Py_DecRef() accepts NULL whereas _Py_IncRef() doesn't. static inline void Py_DECREF(PyObject *op) { # if Py_LIMITED_API+0 >= 0x030a00A7 _Py_DecRef(op); diff --git a/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst b/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst new file mode 100644 index 00000000000000..d7ee7d2eb9d908 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-09-12-35-55.gh-issue-105387.wM_oL-.rst @@ -0,0 +1,3 @@ +In the limited C API version 3.12, :c:func:`Py_INCREF` and +:c:func:`Py_DECREF` functions are now implemented as opaque function calls +to hide implementation details. Patch by Victor Stinner. From fcf0647cf2a78de2c2b603af2709d58c8567df67 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 13 Jun 2023 18:39:18 -0600 Subject: [PATCH 025/446] gh-104812: Skip Pending Calls Tests if No Threading (gh-105761) This fixes the WASM buildbots. --- Lib/test/test_capi/test_misc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 58e1a83da5c146..ccec27d3e0b64c 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1406,6 +1406,7 @@ def wait_for_result(self): while self.result is None: time.sleep(0.01) + @threading_helper.requires_working_threading() def test_subthreads_can_handle_pending_calls(self): payload = 'Spam spam spam spam. Lovely spam! Wonderful spam!' @@ -1421,6 +1422,7 @@ def do_the_work(): self.assertEqual(task.result, payload) + @threading_helper.requires_working_threading() def test_many_subthreads_can_handle_pending_calls(self): main_tid = threading.get_ident() self.assertEqual(threading.main_thread().ident, main_tid) From b87d2882754a7c273e2695c33384383eba380d7d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 13 Jun 2023 18:58:23 -0600 Subject: [PATCH 026/446] gh-105699: Use a Thread-Local Variable for PKGCONTEXT (gh-105740) This fixes a race during import. The existing _PyRuntimeState.imports.pkgcontext is shared between interpreters, and occasionally this would cause a crash when multiple interpreters were importing extensions modules at the same time. To solve this we add a thread-local variable for the value. We also leave the existing state (and infrequent race) in place for platforms that do not support thread-local variables. --- Python/import.c | 15 +++++++++++++++ Tools/c-analyzer/c_parser/parser/_regexes.py | 3 ++- Tools/c-analyzer/c_parser/preprocessor/gcc.py | 1 + Tools/c-analyzer/cpython/ignored.tsv | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Python/import.c b/Python/import.c index 71cce8e4f623dd..779af55347a614 100644 --- a/Python/import.c +++ b/Python/import.c @@ -703,10 +703,19 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp) _PyRuntime.imports.pkgcontext, and PyModule_Create*() will substitute this (if the name actually matches). */ + +#ifdef HAVE_THREAD_LOCAL +_Py_thread_local const char *pkgcontext = NULL; +# undef PKGCONTEXT +# define PKGCONTEXT pkgcontext +#endif + const char * _PyImport_ResolveNameWithPackageContext(const char *name) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif if (PKGCONTEXT != NULL) { const char *p = strrchr(PKGCONTEXT, '.'); if (p != NULL && strcmp(name, p+1) == 0) { @@ -714,17 +723,23 @@ _PyImport_ResolveNameWithPackageContext(const char *name) PKGCONTEXT = NULL; } } +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return name; } const char * _PyImport_SwapPackageContext(const char *newcontext) { +#ifndef HAVE_THREAD_LOCAL PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK); +#endif const char *oldcontext = PKGCONTEXT; PKGCONTEXT = newcontext; +#ifndef HAVE_THREAD_LOCAL PyThread_release_lock(EXTENSIONS.mutex); +#endif return oldcontext; } diff --git a/Tools/c-analyzer/c_parser/parser/_regexes.py b/Tools/c-analyzer/c_parser/parser/_regexes.py index b7f22b186f4965..5695daff67d6bd 100644 --- a/Tools/c-analyzer/c_parser/parser/_regexes.py +++ b/Tools/c-analyzer/c_parser/parser/_regexes.py @@ -58,6 +58,7 @@ def _ind(text, level=1, edges='both'): extern | register | static | + _Thread_local | typedef | const | @@ -137,7 +138,7 @@ def _ind(text, level=1, edges='both'): ####################################### # variable declarations -_STORAGE = 'auto register static extern'.split() +_STORAGE = 'auto register static extern _Thread_local'.split() STORAGE_CLASS = rf'(?: \b (?: {" | ".join(_STORAGE)} ) \b )' TYPE_QUALIFIER = r'(?: \b (?: const | volatile ) \b )' PTR_QUALIFIER = rf'(?: [*] (?: \s* {TYPE_QUALIFIER} )? )' diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index c680f351f22416..147615707a3cb8 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -219,6 +219,7 @@ def _strip_directives(line, partial=0): line = line[m.end():] line = re.sub(r'__extension__', '', line) + line = re.sub(r'__thread\b', '_Thread_local', line) while (m := COMPILER_DIRECTIVE_RE.match(line)): before, _, _, closed = m.groups() diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 87d9b39c16113b..c58dfe2d0b944e 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -168,6 +168,12 @@ Modules/_xxinterpchannelsmodule.c - _globals - Python/pyfpe.c - PyFPE_counter - +##----------------------- +## thread-local variables + +Python/import.c - pkgcontext - +Python/pystate.c - _Py_tss_tstate - + ##----------------------- ## should be const # XXX Make them const. From ac7b551bde7a362bc77d2cb84accf755ac30eb09 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 04:46:47 +0200 Subject: [PATCH 027/446] gh-105751: test_ctypes gets Windows attrs from ctypes (#105758) test_ctypes now gets attributes specific to Windows from the ctypes module, rather than relying on "from ctypes import *". Attributes: * ctypes.FormatError * ctypes.WINFUNCTYPE * ctypes.WinError * ctypes.WinDLL * ctypes.windll * ctypes.oledll * ctypes.get_last_error() * ctypes.set_last_error() --- Lib/test/test_ctypes/test_as_parameter.py | 5 ++-- Lib/test/test_ctypes/test_callbacks.py | 18 +++++++-------- Lib/test/test_ctypes/test_cfuncs.py | 14 ++++------- Lib/test/test_ctypes/test_checkretval.py | 6 ++--- Lib/test/test_ctypes/test_errno.py | 19 +++++++-------- Lib/test/test_ctypes/test_funcptr.py | 9 ++++---- Lib/test/test_ctypes/test_functions.py | 7 +++--- Lib/test/test_ctypes/test_loading.py | 27 ++++++++++++---------- Lib/test/test_ctypes/test_pointers.py | 3 ++- Lib/test/test_ctypes/test_random_things.py | 15 +++++++----- Lib/test/test_ctypes/test_win32.py | 16 ++++++++----- 11 files changed, 75 insertions(+), 64 deletions(-) diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index e9ec9ad847b487..fcf99ff057920b 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -1,4 +1,5 @@ import unittest +import ctypes from ctypes import * from test.test_ctypes import need_symbol import _ctypes_test @@ -6,8 +7,8 @@ dll = CDLL(_ctypes_test.__file__) try: - CALLBACK_FUNCTYPE = WINFUNCTYPE -except NameError: + CALLBACK_FUNCTYPE = ctypes.WINFUNCTYPE +except AttributeError: # fake to enable this test on Linux CALLBACK_FUNCTYPE = CFUNCTYPE diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index b185e388ab1527..a5c2e430d85ad0 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -2,6 +2,7 @@ import unittest from test import support +import ctypes from ctypes import * from test.test_ctypes import need_symbol from _ctypes import CTYPES_MAX_ARGCOUNT @@ -152,7 +153,7 @@ def __del__(self): @need_symbol('WINFUNCTYPE') def test_i38748_stackCorruption(self): - callback_funcType = WINFUNCTYPE(c_long, c_long, c_longlong) + callback_funcType = ctypes.WINFUNCTYPE(c_long, c_long, c_longlong) @callback_funcType def callback(a, b): c = a + b @@ -163,12 +164,10 @@ def callback(a, b): self.assertEqual(dll._test_i38748_runCallback(callback, 5, 10), 15) -@need_symbol('WINFUNCTYPE') -class StdcallCallbacks(Callbacks): - try: - functype = WINFUNCTYPE - except NameError: - pass +if hasattr(ctypes, 'WINFUNCTYPE'): + class StdcallCallbacks(Callbacks): + functype = ctypes.WINFUNCTYPE + ################################################################ @@ -216,13 +215,14 @@ def test_issue_8959_b(self): global windowCount windowCount = 0 - @WINFUNCTYPE(BOOL, HWND, LPARAM) + @ctypes.WINFUNCTYPE(BOOL, HWND, LPARAM) def EnumWindowsCallbackFunc(hwnd, lParam): global windowCount windowCount += 1 return True #Allow windows to keep enumerating - windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0) + user32 = ctypes.windll.user32 + user32.EnumWindows(EnumWindowsCallbackFunc, 0) def test_callback_register_int(self): # Issue #8275: buggy handling of callback args under Win64 diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py index 7cba4b0e527f4d..d66e679799c543 100644 --- a/Lib/test/test_ctypes/test_cfuncs.py +++ b/Lib/test/test_ctypes/test_cfuncs.py @@ -2,6 +2,7 @@ # Byte order related? import unittest +import ctypes from ctypes import * from test.test_ctypes import need_symbol @@ -197,12 +198,8 @@ def test_void(self): # The following repeats the above tests with stdcall functions (where # they are available) -try: - WinDLL -except NameError: - def stdcall_dll(*_): pass -else: - class stdcall_dll(WinDLL): +if hasattr(ctypes, 'WinDLL'): + class stdcall_dll(ctypes.WinDLL): def __getattr__(self, name): if name[:2] == '__' and name[-2:] == '__': raise AttributeError(name) @@ -210,9 +207,8 @@ def __getattr__(self, name): setattr(self, name, func) return func -@need_symbol('WinDLL') -class stdcallCFunctions(CFunctions): - _dll = stdcall_dll(_ctypes_test.__file__) + class stdcallCFunctions(CFunctions): + _dll = stdcall_dll(_ctypes_test.__file__) if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_checkretval.py b/Lib/test/test_ctypes/test_checkretval.py index 1492099f4b9e99..b4834322ea7f8a 100644 --- a/Lib/test/test_ctypes/test_checkretval.py +++ b/Lib/test/test_ctypes/test_checkretval.py @@ -1,5 +1,6 @@ import unittest +import ctypes from ctypes import * from test.test_ctypes import need_symbol @@ -28,9 +29,8 @@ def test_checkretval(self): @need_symbol('oledll') def test_oledll(self): - self.assertRaises(OSError, - oledll.oleaut32.CreateTypeLib2, - 0, None, None) + oleaut32 = ctypes.oledll.oleaut32 + self.assertRaises(OSError, oleaut32.CreateTypeLib2, 0, None, None) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_errno.py b/Lib/test/test_ctypes/test_errno.py index 3685164dde6214..bfc20bd68fc7f0 100644 --- a/Lib/test/test_ctypes/test_errno.py +++ b/Lib/test/test_ctypes/test_errno.py @@ -1,6 +1,7 @@ import unittest, os, errno import threading +import ctypes from ctypes import * from ctypes.util import find_library @@ -44,33 +45,33 @@ def _worker(): @unittest.skipUnless(os.name == "nt", 'Test specific to Windows') def test_GetLastError(self): - dll = WinDLL("kernel32", use_last_error=True) + dll = ctypes.WinDLL("kernel32", use_last_error=True) GetModuleHandle = dll.GetModuleHandleA GetModuleHandle.argtypes = [c_wchar_p] self.assertEqual(0, GetModuleHandle("foo")) - self.assertEqual(get_last_error(), 126) + self.assertEqual(ctypes.get_last_error(), 126) - self.assertEqual(set_last_error(32), 126) - self.assertEqual(get_last_error(), 32) + self.assertEqual(ctypes.set_last_error(32), 126) + self.assertEqual(ctypes.get_last_error(), 32) def _worker(): - set_last_error(0) + ctypes.set_last_error(0) - dll = WinDLL("kernel32", use_last_error=False) + dll = ctypes.WinDLL("kernel32", use_last_error=False) GetModuleHandle = dll.GetModuleHandleW GetModuleHandle.argtypes = [c_wchar_p] GetModuleHandle("bar") - self.assertEqual(get_last_error(), 0) + self.assertEqual(ctypes.get_last_error(), 0) t = threading.Thread(target=_worker) t.start() t.join() - self.assertEqual(get_last_error(), 32) + self.assertEqual(ctypes.get_last_error(), 32) - set_last_error(0) + ctypes.set_last_error(0) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_funcptr.py b/Lib/test/test_ctypes/test_funcptr.py index e0b9b54e97f673..ef6772c6e88b65 100644 --- a/Lib/test/test_ctypes/test_funcptr.py +++ b/Lib/test/test_ctypes/test_funcptr.py @@ -1,9 +1,10 @@ import unittest +import ctypes from ctypes import * try: - WINFUNCTYPE -except NameError: + WINFUNCTYPE = ctypes.WINFUNCTYPE +except AttributeError: # fake to enable this test on Linux WINFUNCTYPE = CFUNCTYPE @@ -39,7 +40,7 @@ def func(a, b): # possible, as in C, to call cdecl functions with more parameters. #self.assertRaises(TypeError, c, 1, 2, 3) self.assertEqual(c(1, 2, 3, 4, 5, 6), 3) - if not WINFUNCTYPE is CFUNCTYPE: + if WINFUNCTYPE is not CFUNCTYPE: self.assertRaises(TypeError, s, 1, 2, 3) def test_structures(self): @@ -91,7 +92,7 @@ def test_dllfunctions(self): def NoNullHandle(value): if not value: - raise WinError() + raise ctypes.WinError() return value strchr = lib.my_strchr diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index 703bd2c601ccf6..3f331703a0db22 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -5,20 +5,21 @@ Later... """ +import ctypes from ctypes import * from test.test_ctypes import need_symbol import sys, unittest try: - WINFUNCTYPE -except NameError: + WINFUNCTYPE = ctypes.WINFUNCTYPE +except AttributeError: # fake to enable this test on Linux WINFUNCTYPE = CFUNCTYPE import _ctypes_test dll = CDLL(_ctypes_test.__file__) if sys.platform == "win32": - windll = WinDLL(_ctypes_test.__file__) + windll = ctypes.WinDLL(_ctypes_test.__file__) class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py index f2434926a51714..fec26aab1d8031 100644 --- a/Lib/test/test_ctypes/test_loading.py +++ b/Lib/test/test_ctypes/test_loading.py @@ -1,4 +1,5 @@ from ctypes import * +import ctypes import os import shutil import subprocess @@ -72,18 +73,18 @@ def test_load_library(self): print(find_library("user32")) if os.name == "nt": - windll.kernel32.GetModuleHandleW - windll["kernel32"].GetModuleHandleW - windll.LoadLibrary("kernel32").GetModuleHandleW - WinDLL("kernel32").GetModuleHandleW + ctypes.windll.kernel32.GetModuleHandleW + ctypes.windll["kernel32"].GetModuleHandleW + ctypes.windll.LoadLibrary("kernel32").GetModuleHandleW + ctypes.WinDLL("kernel32").GetModuleHandleW # embedded null character - self.assertRaises(ValueError, windll.LoadLibrary, "kernel32\0") + self.assertRaises(ValueError, ctypes.windll.LoadLibrary, "kernel32\0") @unittest.skipUnless(os.name == "nt", 'test specific to Windows') def test_load_ordinal_functions(self): import _ctypes_test - dll = WinDLL(_ctypes_test.__file__) + dll = ctypes.WinDLL(_ctypes_test.__file__) # We load the same function both via ordinal and name func_ord = dll[2] func_name = dll.GetString @@ -114,14 +115,16 @@ def test_1703286_B(self): # also has a high address. 'call_function' should accept # addresses so large. from _ctypes import call_function - advapi32 = windll.advapi32 + + advapi32 = ctypes.windll.advapi32 # Calling CloseEventLog with a NULL argument should fail, # but the call should not segfault or so. self.assertEqual(0, advapi32.CloseEventLog(None)) - windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p - windll.kernel32.GetProcAddress.restype = c_void_p - proc = windll.kernel32.GetProcAddress(advapi32._handle, - b"CloseEventLog") + + kernel32 = ctypes.windll.kernel32 + kernel32.GetProcAddress.argtypes = c_void_p, c_char_p + kernel32.GetProcAddress.restype = c_void_p + proc = kernel32.GetProcAddress(advapi32._handle, b"CloseEventLog") self.assertTrue(proc) # This is the real test: call the function via 'call_function' self.assertEqual(0, call_function(proc, (None,))) @@ -130,7 +133,7 @@ def test_1703286_B(self): 'test specific to Windows') def test_load_hasattr(self): # bpo-34816: shouldn't raise OSError - self.assertFalse(hasattr(windll, 'test')) + self.assertFalse(hasattr(ctypes.windll, 'test')) @unittest.skipUnless(os.name == "nt", 'test specific to Windows') diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index e97515879f1f0e..7b6c3f5babe481 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -1,5 +1,6 @@ import unittest, sys +import ctypes from ctypes import * import _ctypes_test @@ -193,7 +194,7 @@ def test_pointers_bool(self): # COM methods are boolean True: if sys.platform == "win32": - mth = WINFUNCTYPE(None)(42, "name", (), None) + mth = ctypes.WINFUNCTYPE(None)(42, "name", (), None) self.assertEqual(bool(mth), True) def test_pointer_type_name(self): diff --git a/Lib/test/test_ctypes/test_random_things.py b/Lib/test/test_ctypes/test_random_things.py index 2988e275cf4bbf..cfd355a7f0835f 100644 --- a/Lib/test/test_ctypes/test_random_things.py +++ b/Lib/test/test_ctypes/test_random_things.py @@ -1,4 +1,5 @@ from ctypes import * +import ctypes import contextlib from test import support import unittest @@ -16,15 +17,17 @@ class call_function_TestCase(unittest.TestCase): def test(self): from _ctypes import call_function - windll.kernel32.LoadLibraryA.restype = c_void_p - windll.kernel32.GetProcAddress.argtypes = c_void_p, c_char_p - windll.kernel32.GetProcAddress.restype = c_void_p - hdll = windll.kernel32.LoadLibraryA(b"kernel32") - funcaddr = windll.kernel32.GetProcAddress(hdll, b"GetModuleHandleA") + kernel32 = ctypes.windll.kernel32 + kernel32.LoadLibraryA.restype = c_void_p + kernel32.GetProcAddress.argtypes = c_void_p, c_char_p + kernel32.GetProcAddress.restype = c_void_p + + hdll = kernel32.LoadLibraryA(b"kernel32") + funcaddr = kernel32.GetProcAddress(hdll, b"GetModuleHandleA") self.assertEqual(call_function(funcaddr, (None,)), - windll.kernel32.GetModuleHandleA(None)) + kernel32.GetModuleHandleA(None)) class CallbackTracbackTestCase(unittest.TestCase): # When an exception is raised in a ctypes callback function, the C diff --git a/Lib/test/test_ctypes/test_win32.py b/Lib/test/test_ctypes/test_win32.py index e51bdc8ad6b071..43ed9dbe10c28e 100644 --- a/Lib/test/test_ctypes/test_win32.py +++ b/Lib/test/test_ctypes/test_win32.py @@ -1,5 +1,6 @@ # Windows specific tests +import ctypes from ctypes import * import unittest, sys from test import support @@ -14,15 +15,17 @@ class FunctionCallTestCase(unittest.TestCase): def test_SEH(self): # Disable faulthandler to prevent logging the warning: # "Windows fatal exception: access violation" + kernel32 = ctypes.windll.kernel32 with support.disable_faulthandler(): # Call functions with invalid arguments, and make sure # that access violations are trapped and raise an # exception. - self.assertRaises(OSError, windll.kernel32.GetModuleHandleA, 32) + self.assertRaises(OSError, kernel32.GetModuleHandleA, 32) def test_noargs(self): # This is a special case on win32 x64 - windll.user32.GetDesktopWindow() + user32 = ctypes.windll.user32 + user32.GetDesktopWindow() @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') @@ -73,17 +76,18 @@ def test_winerror(self): # see Issue 16169 import errno ERROR_INVALID_PARAMETER = 87 - msg = FormatError(ERROR_INVALID_PARAMETER).strip() + msg = ctypes.FormatError(ERROR_INVALID_PARAMETER).strip() args = (errno.EINVAL, msg, None, ERROR_INVALID_PARAMETER) - e = WinError(ERROR_INVALID_PARAMETER) + e = ctypes.WinError(ERROR_INVALID_PARAMETER) self.assertEqual(e.args, args) self.assertEqual(e.errno, errno.EINVAL) self.assertEqual(e.winerror, ERROR_INVALID_PARAMETER) - windll.kernel32.SetLastError(ERROR_INVALID_PARAMETER) + kernel32 = ctypes.windll.kernel32 + kernel32.SetLastError(ERROR_INVALID_PARAMETER) try: - raise WinError() + raise ctypes.WinError() except OSError as exc: e = exc self.assertEqual(e.args, args) From 381a1dc26162e9fcbec48ac2eee5ac8adb806b07 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 04:47:01 +0200 Subject: [PATCH 028/446] gh-105751: test_ctypes.test_numbers uses top level imports (#105762) Moroever, c_ulonglong and c_bool are always available. --- Lib/test/test_ctypes/test_numbers.py | 40 ++++++---------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index db500e812beb15..aad6af4b8671ce 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -1,6 +1,10 @@ -from ctypes import * -import unittest import struct +import sys +import unittest +from array import array +from operator import truth +from ctypes import * +from ctypes import _SimpleCData def valid_ranges(*types): # given a sequence of numeric types, collect their _type_ @@ -21,29 +25,11 @@ def valid_ranges(*types): ArgType = type(byref(c_int(0))) -unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong] +unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong] signed_types = [c_byte, c_short, c_int, c_long, c_longlong] - -bool_types = [] - +bool_types = [c_bool] float_types = [c_double, c_float] -try: - c_ulonglong - c_longlong -except NameError: - pass -else: - unsigned_types.append(c_ulonglong) - signed_types.append(c_longlong) - -try: - c_bool -except NameError: - pass -else: - bool_types.append(c_bool) - unsigned_ranges = valid_ranges(*unsigned_types) signed_ranges = valid_ranges(*signed_types) bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] @@ -71,7 +57,6 @@ def test_signed_values(self): self.assertEqual(t(h).value, h) def test_bool_values(self): - from operator import truth for t, v in zip(bool_types, bool_values): self.assertEqual(t(v).value, truth(v)) @@ -161,7 +146,6 @@ def test_alignments(self): (code, align)) def test_int_from_address(self): - from array import array for t in signed_types + unsigned_types: # the array module doesn't support all format codes # (no 'q' or 'Q') @@ -182,7 +166,6 @@ def test_int_from_address(self): def test_float_from_address(self): - from array import array for t in float_types: a = array(t._type_, [3.14]) v = t.from_address(a.buffer_info()[0]) @@ -193,9 +176,6 @@ def test_float_from_address(self): self.assertIs(type(v), t) def test_char_from_address(self): - from ctypes import c_char - from array import array - a = array('b', [0]) a[0] = ord('x') v = c_char.from_address(a.buffer_info()[0]) @@ -208,8 +188,6 @@ def test_char_from_address(self): # array does not support c_bool / 't' @unittest.skip('test disabled') def test_bool_from_address(self): - from ctypes import c_bool - from array import array a = array(c_bool._type_, [True]) v = t.from_address(a.buffer_info()[0]) self.assertEqual(v.value, a[0]) @@ -225,7 +203,6 @@ def test_init(self): self.assertRaises(TypeError, c_int, c_long(42)) def test_float_overflow(self): - import sys big_int = int(sys.float_info.max) * 2 for t in float_types + [c_longdouble]: self.assertRaises(OverflowError, t, big_int) @@ -238,7 +215,6 @@ def test_float_overflow(self): def test_perf(self): check_perf() -from ctypes import _SimpleCData class c_int_S(_SimpleCData): _type_ = "i" __slots__ = [] From b95de96268b334f9ec0aa70bd038f3603bf19421 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 05:34:11 +0200 Subject: [PATCH 029/446] gh-105751: test_ctypes avoids "from ctypes import *" (#105768) Using "import *" prevents linters like pyflakes to detect undefined names (usually missing imports). Replace c_voidp with c_void_p. --- Lib/ctypes/_endian.py | 2 +- Lib/test/test_ctypes/test_anon.py | 2 +- Lib/test/test_ctypes/test_array_in_pointer.py | 2 +- Lib/test/test_ctypes/test_arrays.py | 5 ++++- Lib/test/test_ctypes/test_as_parameter.py | 10 +++++++--- Lib/test/test_ctypes/test_bitfields.py | 6 +++++- Lib/test/test_ctypes/test_buffers.py | 3 ++- Lib/test/test_ctypes/test_bytes.py | 4 ++-- Lib/test/test_ctypes/test_byteswap.py | 8 +++++++- Lib/test/test_ctypes/test_callbacks.py | 7 ++++++- Lib/test/test_ctypes/test_cast.py | 10 ++++++---- Lib/test/test_ctypes/test_cfuncs.py | 12 +++++++----- Lib/test/test_ctypes/test_checkretval.py | 9 ++++++--- Lib/test/test_ctypes/test_delattr.py | 5 ++++- Lib/test/test_ctypes/test_errno.py | 6 ++++-- Lib/test/test_ctypes/test_find.py | 11 +++++++---- Lib/test/test_ctypes/test_frombuffer.py | 2 +- Lib/test/test_ctypes/test_funcptr.py | 13 ++++++++----- Lib/test/test_ctypes/test_functions.py | 6 +++++- Lib/test/test_ctypes/test_incomplete.py | 2 +- Lib/test/test_ctypes/test_init.py | 5 ++++- Lib/test/test_ctypes/test_internals.py | 2 +- Lib/test/test_ctypes/test_keeprefs.py | 2 +- Lib/test/test_ctypes/test_libc.py | 7 +++++-- Lib/test/test_ctypes/test_loading.py | 10 +++++----- Lib/test/test_ctypes/test_memfunctions.py | 6 +++++- Lib/test/test_ctypes/test_numbers.py | 6 ++++-- Lib/test/test_ctypes/test_objects.py | 2 +- Lib/test/test_ctypes/test_pep3118.py | 7 ++++++- Lib/test/test_ctypes/test_pickling.py | 6 +++++- Lib/test/test_ctypes/test_pointers.py | 11 +++++++---- Lib/test/test_ctypes/test_prototypes.py | 5 ++++- Lib/test/test_ctypes/test_python_api.py | 5 ++++- Lib/test/test_ctypes/test_random_things.py | 8 ++++---- Lib/test/test_ctypes/test_repr.py | 5 ++++- Lib/test/test_ctypes/test_returnfuncptrs.py | 3 ++- Lib/test/test_ctypes/test_simplesubclasses.py | 5 ++++- Lib/test/test_ctypes/test_sizes.py | 6 ++++-- Lib/test/test_ctypes/test_slicing.py | 3 ++- Lib/test/test_ctypes/test_stringptr.py | 2 +- Lib/test/test_ctypes/test_strings.py | 2 +- Lib/test/test_ctypes/test_struct_fields.py | 2 +- Lib/test/test_ctypes/test_structures.py | 6 +++++- Lib/test/test_ctypes/test_unaligned_structures.py | 5 ++++- Lib/test/test_ctypes/test_values.py | 2 +- Lib/test/test_ctypes/test_varsize_struct.py | 2 +- Lib/test/test_ctypes/test_win32.py | 10 +++++++--- Lib/test/test_ctypes/test_wintypes.py | 2 +- 48 files changed, 179 insertions(+), 83 deletions(-) diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py index b5446c049bc9dc..3febb3118b8230 100644 --- a/Lib/ctypes/_endian.py +++ b/Lib/ctypes/_endian.py @@ -1,5 +1,5 @@ import sys -from ctypes import * +from ctypes import Array, Structure, Union _array_type = type(Array) diff --git a/Lib/test/test_ctypes/test_anon.py b/Lib/test/test_ctypes/test_anon.py index d378392ebe2844..704f7a3d38a5ac 100644 --- a/Lib/test/test_ctypes/test_anon.py +++ b/Lib/test/test_ctypes/test_anon.py @@ -1,6 +1,6 @@ import unittest import test.support -from ctypes import * +from ctypes import c_int, Union, Structure, sizeof class AnonTest(unittest.TestCase): diff --git a/Lib/test/test_ctypes/test_array_in_pointer.py b/Lib/test/test_ctypes/test_array_in_pointer.py index ca1edcf6210176..a149aa9463f30c 100644 --- a/Lib/test/test_ctypes/test_array_in_pointer.py +++ b/Lib/test/test_ctypes/test_array_in_pointer.py @@ -1,5 +1,5 @@ import unittest -from ctypes import * +from ctypes import c_byte, Structure, POINTER, cast from binascii import hexlify import re diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 473083870ca6e5..4f8747d46ae366 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -2,7 +2,10 @@ import sys import unittest import warnings -from ctypes import * +from ctypes import (Structure, Array, sizeof, addressof, + create_string_buffer, create_unicode_buffer, + c_char, c_wchar, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, + c_long, c_ulonglong, c_float, c_double, c_longdouble) from test.support import bigmemtest, _2G from test.test_ctypes import need_symbol diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index fcf99ff057920b..1048c5064c3c17 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -1,8 +1,12 @@ -import unittest +import _ctypes_test import ctypes -from ctypes import * +import unittest +from ctypes import (Structure, CDLL, CFUNCTYPE, + POINTER, pointer, byref, + c_short, c_int, c_long, c_longlong, + c_byte, c_wchar, c_float, c_double, + ArgumentError) from test.test_ctypes import need_symbol -import _ctypes_test dll = CDLL(_ctypes_test.__file__) diff --git a/Lib/test/test_ctypes/test_bitfields.py b/Lib/test/test_ctypes/test_bitfields.py index dad71a0ba7ee4a..e7b06dd767f9ea 100644 --- a/Lib/test/test_ctypes/test_bitfields.py +++ b/Lib/test/test_ctypes/test_bitfields.py @@ -1,4 +1,8 @@ -from ctypes import * +from ctypes import (CDLL, Structure, sizeof, POINTER, byref, alignment, + LittleEndianStructure, BigEndianStructure, + c_byte, c_ubyte, c_char, c_char_p, c_void_p, c_wchar, + c_uint32, c_uint64, + c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong) from test.test_ctypes import need_symbol from test import support import unittest diff --git a/Lib/test/test_ctypes/test_buffers.py b/Lib/test/test_ctypes/test_buffers.py index a9be2023aa0fa0..c6c59b926798e0 100644 --- a/Lib/test/test_ctypes/test_buffers.py +++ b/Lib/test/test_ctypes/test_buffers.py @@ -1,4 +1,5 @@ -from ctypes import * +from ctypes import (create_string_buffer, create_unicode_buffer, sizeof, + c_char, c_wchar) from test.test_ctypes import need_symbol import unittest diff --git a/Lib/test/test_ctypes/test_bytes.py b/Lib/test/test_ctypes/test_bytes.py index 092ec5af0524c4..3538ed7d7197cc 100644 --- a/Lib/test/test_ctypes/test_bytes.py +++ b/Lib/test/test_ctypes/test_bytes.py @@ -1,7 +1,7 @@ """Test where byte objects are accepted""" -import unittest import sys -from ctypes import * +import unittest +from ctypes import Structure, c_char, c_char_p, c_wchar, c_wchar_p class BytesTest(unittest.TestCase): def test_c_char(self): diff --git a/Lib/test/test_ctypes/test_byteswap.py b/Lib/test/test_ctypes/test_byteswap.py index 7e98559dfbccb6..7507c07d8a8a95 100644 --- a/Lib/test/test_ctypes/test_byteswap.py +++ b/Lib/test/test_ctypes/test_byteswap.py @@ -1,7 +1,13 @@ import sys, unittest, struct, math, ctypes from binascii import hexlify -from ctypes import * +from ctypes import (Structure, Union, LittleEndianUnion, BigEndianUnion, + BigEndianStructure, LittleEndianStructure, + POINTER, sizeof, cast, + c_byte, c_ubyte, c_char, c_wchar, c_void_p, + c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, + c_uint32, c_float, c_double) def bin(s): return hexlify(memoryview(s)).decode().upper() diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index a5c2e430d85ad0..7ce9775978fa4b 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -3,7 +3,12 @@ from test import support import ctypes -from ctypes import * +from ctypes import (CDLL, cdll, Structure, CFUNCTYPE, + ArgumentError, POINTER, sizeof, + c_byte, c_ubyte, c_char, c_char_p, + c_short, c_ushort, c_int, c_uint, + c_long, c_longlong, c_ulonglong, c_ulong, + c_float, c_double, c_longdouble, py_object) from test.test_ctypes import need_symbol from _ctypes import CTYPES_MAX_ARGCOUNT import _ctypes_test diff --git a/Lib/test/test_ctypes/test_cast.py b/Lib/test/test_ctypes/test_cast.py index 7ee23b16f1b00b..641b0783515c65 100644 --- a/Lib/test/test_ctypes/test_cast.py +++ b/Lib/test/test_ctypes/test_cast.py @@ -1,7 +1,9 @@ -from ctypes import * -from test.test_ctypes import need_symbol -import unittest import sys +import unittest +from ctypes import (Structure, Union, POINTER, cast, sizeof, addressof, + c_void_p, c_char_p, c_wchar_p, + c_byte, c_short, c_int) +from test.test_ctypes import need_symbol class Test(unittest.TestCase): @@ -12,7 +14,7 @@ def test_array2pointer(self): ptr = cast(array, POINTER(c_int)) self.assertEqual([ptr[i] for i in range(3)], [42, 17, 2]) - if 2*sizeof(c_short) == sizeof(c_int): + if 2 * sizeof(c_short) == sizeof(c_int): ptr = cast(array, POINTER(c_short)) if sys.byteorder == "little": self.assertEqual([ptr[i] for i in range(6)], diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py index d66e679799c543..9cbde8a13091f2 100644 --- a/Lib/test/test_ctypes/test_cfuncs.py +++ b/Lib/test/test_ctypes/test_cfuncs.py @@ -1,13 +1,14 @@ -# A lot of failures in these tests on Mac OS X. -# Byte order related? - import unittest import ctypes -from ctypes import * +from ctypes import (CDLL, + c_byte, c_ubyte, c_char, + c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, + c_float, c_double, c_longdouble) from test.test_ctypes import need_symbol - import _ctypes_test + class CFunctions(unittest.TestCase): _dll = CDLL(_ctypes_test.__file__) @@ -210,5 +211,6 @@ def __getattr__(self, name): class stdcallCFunctions(CFunctions): _dll = stdcall_dll(_ctypes_test.__file__) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_checkretval.py b/Lib/test/test_ctypes/test_checkretval.py index b4834322ea7f8a..fe5f2442cd7b4e 100644 --- a/Lib/test/test_ctypes/test_checkretval.py +++ b/Lib/test/test_ctypes/test_checkretval.py @@ -1,15 +1,16 @@ -import unittest - import ctypes -from ctypes import * +import unittest +from ctypes import CDLL, c_int from test.test_ctypes import need_symbol + class CHECKED(c_int): def _check_retval_(value): # Receives a CHECKED instance. return str(value.value) _check_retval_ = staticmethod(_check_retval_) + class Test(unittest.TestCase): def test_checkretval(self): @@ -32,5 +33,7 @@ def test_oledll(self): oleaut32 = ctypes.oledll.oleaut32 self.assertRaises(OSError, oleaut32.CreateTypeLib2, 0, None, None) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_delattr.py b/Lib/test/test_ctypes/test_delattr.py index 0f4d58691b55e7..10d2fe066fc068 100644 --- a/Lib/test/test_ctypes/test_delattr.py +++ b/Lib/test/test_ctypes/test_delattr.py @@ -1,9 +1,11 @@ import unittest -from ctypes import * +from ctypes import Structure, c_char, c_int + class X(Structure): _fields_ = [("foo", c_int)] + class TestCase(unittest.TestCase): def test_simple(self): self.assertRaises(TypeError, @@ -17,5 +19,6 @@ def test_struct(self): self.assertRaises(TypeError, delattr, X(), "foo") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_errno.py b/Lib/test/test_ctypes/test_errno.py index bfc20bd68fc7f0..3376322299d29e 100644 --- a/Lib/test/test_ctypes/test_errno.py +++ b/Lib/test/test_ctypes/test_errno.py @@ -2,14 +2,15 @@ import threading import ctypes -from ctypes import * +from ctypes import CDLL, c_int, c_char_p, c_wchar_p, get_errno, set_errno from ctypes.util import find_library class Test(unittest.TestCase): def test_open(self): libc_name = find_library("c") if libc_name is None: - raise unittest.SkipTest("Unable to find C library") + self.skipTest("Unable to find C library") + libc = CDLL(libc_name, use_errno=True) if os.name == "nt": libc_open = libc._open @@ -73,5 +74,6 @@ def _worker(): ctypes.set_last_error(0) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_find.py b/Lib/test/test_ctypes/test_find.py index 1ff9d019b138a4..7a1658b63cbac7 100644 --- a/Lib/test/test_ctypes/test_find.py +++ b/Lib/test/test_ctypes/test_find.py @@ -1,11 +1,12 @@ -import unittest -import unittest.mock import os.path import sys import test.support -from test.support import os_helper -from ctypes import * +import unittest +import unittest.mock +from ctypes import CDLL, RTLD_GLOBAL from ctypes.util import find_library +from test.support import os_helper + # On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode. class Test_OpenGL_libs(unittest.TestCase): @@ -36,11 +37,13 @@ def setUpClass(cls): cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) except OSError: pass + if lib_glu: try: cls.glu = CDLL(lib_glu, RTLD_GLOBAL) except OSError: pass + if lib_gle: try: cls.gle = CDLL(lib_gle) diff --git a/Lib/test/test_ctypes/test_frombuffer.py b/Lib/test/test_ctypes/test_frombuffer.py index 55c244356b30d0..e3e1267387848e 100644 --- a/Lib/test/test_ctypes/test_frombuffer.py +++ b/Lib/test/test_ctypes/test_frombuffer.py @@ -1,7 +1,7 @@ -from ctypes import * import array import gc import unittest +from ctypes import Structure, Union, Array, sizeof, c_char, c_int class X(Structure): _fields_ = [("c_int", c_int)] diff --git a/Lib/test/test_ctypes/test_funcptr.py b/Lib/test/test_ctypes/test_funcptr.py index ef6772c6e88b65..72684d6d1cd19b 100644 --- a/Lib/test/test_ctypes/test_funcptr.py +++ b/Lib/test/test_ctypes/test_funcptr.py @@ -1,6 +1,8 @@ -import unittest +import _ctypes_test import ctypes -from ctypes import * +import unittest +from ctypes import (CDLL, Structure, CFUNCTYPE, sizeof, + c_void_p, c_char_p, c_char, c_int, c_uint, c_long) try: WINFUNCTYPE = ctypes.WINFUNCTYPE @@ -8,9 +10,9 @@ # fake to enable this test on Linux WINFUNCTYPE = CFUNCTYPE -import _ctypes_test lib = CDLL(_ctypes_test.__file__) + class CFuncPtrTestCase(unittest.TestCase): def test_basic(self): X = WINFUNCTYPE(c_int, c_int, c_int) @@ -21,8 +23,8 @@ def func(*args): x = X(func) self.assertEqual(x.restype, c_int) self.assertEqual(x.argtypes, (c_int, c_int)) - self.assertEqual(sizeof(x), sizeof(c_voidp)) - self.assertEqual(sizeof(X), sizeof(c_voidp)) + self.assertEqual(sizeof(x), sizeof(c_void_p)) + self.assertEqual(sizeof(X), sizeof(c_void_p)) def test_first(self): StdCallback = WINFUNCTYPE(c_int, c_int, c_int) @@ -129,5 +131,6 @@ def test_abstract(self): self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index 3f331703a0db22..a14924a9413cec 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -6,7 +6,11 @@ """ import ctypes -from ctypes import * +from ctypes import (CDLL, Structure, Array, CFUNCTYPE, + byref, POINTER, pointer, ArgumentError, + c_char, c_wchar, c_byte, c_char_p, + c_short, c_int, c_long, c_longlong, + c_float, c_double, c_longdouble) from test.test_ctypes import need_symbol import sys, unittest diff --git a/Lib/test/test_ctypes/test_incomplete.py b/Lib/test/test_ctypes/test_incomplete.py index 0b53c15f1f9986..552effaa3db973 100644 --- a/Lib/test/test_ctypes/test_incomplete.py +++ b/Lib/test/test_ctypes/test_incomplete.py @@ -1,7 +1,7 @@ import ctypes import unittest import warnings -from ctypes import * +from ctypes import Structure, POINTER, pointer, c_char_p ################################################################ # diff --git a/Lib/test/test_ctypes/test_init.py b/Lib/test/test_ctypes/test_init.py index 75fad112a01ffb..113425e5823edc 100644 --- a/Lib/test/test_ctypes/test_init.py +++ b/Lib/test/test_ctypes/test_init.py @@ -1,5 +1,6 @@ -from ctypes import * import unittest +from ctypes import Structure, c_int + class X(Structure): _fields_ = [("a", c_int), @@ -15,6 +16,7 @@ def __init__(self): self.a = 9 self.b = 12 + class Y(Structure): _fields_ = [("x", X)] @@ -36,5 +38,6 @@ def test_get(self): self.assertEqual((y.x.a, y.x.b), (9, 12)) self.assertEqual(y.x.new_was_called, False) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_internals.py b/Lib/test/test_ctypes/test_internals.py index 271e3f57f81743..1290f80111d283 100644 --- a/Lib/test/test_ctypes/test_internals.py +++ b/Lib/test/test_ctypes/test_internals.py @@ -1,6 +1,6 @@ # This tests the internal _objects attribute import unittest -from ctypes import * +from ctypes import Structure, POINTER, c_char_p, c_int from sys import getrefcount as grc # XXX This test must be reviewed for correctness!!! diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index 94c02573fa19d8..ecfcda13945dc6 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -1,4 +1,4 @@ -from ctypes import * +from ctypes import Structure, POINTER, pointer, c_char_p, c_int import unittest class SimpleTestCase(unittest.TestCase): diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 56285b5ff81512..8664529f094476 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -1,10 +1,13 @@ import unittest -from ctypes import * -import _ctypes_test +from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, + c_void_p, c_char, c_int, c_double, c_size_t) + +import _ctypes_test lib = CDLL(_ctypes_test.__file__) + def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" return (x > y) - (x < y) diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py index fec26aab1d8031..0cbfcf01c0cf2b 100644 --- a/Lib/test/test_ctypes/test_loading.py +++ b/Lib/test/test_ctypes/test_loading.py @@ -1,15 +1,15 @@ -from ctypes import * import ctypes import os import shutil import subprocess import sys -import unittest import test.support -from test.support import import_helper -from test.support import os_helper +import unittest +from test.support import import_helper, os_helper +from ctypes import CDLL, cdll, addressof, c_void_p, c_char_p from ctypes.util import find_library + libc_name = None def setUpModule(): @@ -126,6 +126,7 @@ def test_1703286_B(self): kernel32.GetProcAddress.restype = c_void_p proc = kernel32.GetProcAddress(advapi32._handle, b"CloseEventLog") self.assertTrue(proc) + # This is the real test: call the function via 'call_function' self.assertEqual(0, call_function(proc, (None,))) @@ -196,6 +197,5 @@ def should_fail(command): "WinDLL('_sqlite3.dll'); p.close()") - if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py index d5c973521177c8..3f3b6319edb13a 100644 --- a/Lib/test/test_ctypes/test_memfunctions.py +++ b/Lib/test/test_ctypes/test_memfunctions.py @@ -1,7 +1,11 @@ import sys from test import support import unittest -from ctypes import * +from ctypes import (POINTER, sizeof, cast, + create_string_buffer, string_at, + create_unicode_buffer, wstring_at, + memmove, memset, + c_char_p, c_byte, c_ubyte, c_wchar) from test.test_ctypes import need_symbol class MemFunctionsTest(unittest.TestCase): diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index aad6af4b8671ce..061876f9f776d6 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -3,8 +3,10 @@ import unittest from array import array from operator import truth -from ctypes import * -from ctypes import _SimpleCData +from ctypes import (byref, sizeof, alignment, _SimpleCData, + c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, + c_float, c_double, c_longdouble, c_bool) def valid_ranges(*types): # given a sequence of numeric types, collect their _type_ diff --git a/Lib/test/test_ctypes/test_objects.py b/Lib/test/test_ctypes/test_objects.py index 44a3c61ad79267..78b1634115bdb4 100644 --- a/Lib/test/test_ctypes/test_objects.py +++ b/Lib/test/test_ctypes/test_objects.py @@ -11,7 +11,7 @@ Here is an array of string pointers: ->>> from ctypes import * +>>> from ctypes import Structure, c_int, c_char_p >>> array = (c_char_p * 5)() >>> print(array._objects) None diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index 038161745df905..c8eb584858ca9d 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -1,5 +1,10 @@ import unittest -from ctypes import * +from ctypes import (CFUNCTYPE, POINTER, sizeof, Union, + Structure, LittleEndianStructure, BigEndianStructure, + c_char, c_byte, c_ubyte, + c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, c_uint64, + c_bool, c_float, c_double, c_longdouble, py_object) import re, sys if sys.byteorder == "little": diff --git a/Lib/test/test_ctypes/test_pickling.py b/Lib/test/test_ctypes/test_pickling.py index c4a79b977931c8..1df79be9fbac1d 100644 --- a/Lib/test/test_ctypes/test_pickling.py +++ b/Lib/test/test_ctypes/test_pickling.py @@ -1,9 +1,13 @@ import unittest import pickle -from ctypes import * +from ctypes import (CDLL, Structure, CFUNCTYPE, pointer, + c_void_p, c_char_p, c_wchar_p, c_char, c_wchar, c_int, c_double) + + import _ctypes_test dll = CDLL(_ctypes_test.__file__) + class X(Structure): _fields_ = [("a", c_int), ("b", c_double)] init_called = 0 diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index 7b6c3f5babe481..7d13aebdbbeafe 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -1,8 +1,11 @@ -import unittest, sys - -import ctypes -from ctypes import * import _ctypes_test +import ctypes +import sys +import unittest +from ctypes import (CDLL, CFUNCTYPE, Structure, POINTER, pointer, byref, sizeof, + c_void_p, c_char_p, + c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, + c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) ctype_types = [c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float] diff --git a/Lib/test/test_ctypes/test_prototypes.py b/Lib/test/test_ctypes/test_prototypes.py index bf27561487ac81..fe620439a25b29 100644 --- a/Lib/test/test_ctypes/test_prototypes.py +++ b/Lib/test/test_ctypes/test_prototypes.py @@ -1,4 +1,7 @@ -from ctypes import * +from ctypes import (CDLL, CFUNCTYPE, POINTER, ArgumentError, + pointer, byref, sizeof, addressof, + c_void_p, c_char_p, c_wchar_p, c_char, c_wchar, c_buffer, + c_short, c_int, c_long, c_longlong, c_double) from test.test_ctypes import need_symbol import unittest diff --git a/Lib/test/test_ctypes/test_python_api.py b/Lib/test/test_ctypes/test_python_api.py index de8989e2c3300f..3799311751a055 100644 --- a/Lib/test/test_ctypes/test_python_api.py +++ b/Lib/test/test_ctypes/test_python_api.py @@ -1,6 +1,8 @@ -from ctypes import * import unittest from test import support +from ctypes import (pythonapi, POINTER, c_buffer, sizeof, + py_object, c_char_p, c_char, c_long, c_size_t) + ################################################################ # This section should be moved into ctypes\__init__.py, when it's ready. @@ -82,5 +84,6 @@ def test_pyobject_repr(self): self.assertEqual(repr(py_object(42)), "py_object(42)") self.assertEqual(repr(py_object(object)), "py_object(%r)" % object) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_random_things.py b/Lib/test/test_ctypes/test_random_things.py index cfd355a7f0835f..fcea8e847eb606 100644 --- a/Lib/test/test_ctypes/test_random_things.py +++ b/Lib/test/test_ctypes/test_random_things.py @@ -1,9 +1,9 @@ -from ctypes import * -import ctypes import contextlib -from test import support -import unittest +import ctypes import sys +import unittest +from test import support +from ctypes import CFUNCTYPE, c_void_p, c_char_p, c_int, c_double def callback_func(arg): diff --git a/Lib/test/test_ctypes/test_repr.py b/Lib/test/test_ctypes/test_repr.py index 60a2c803453d53..bb6b5ae5e799fd 100644 --- a/Lib/test/test_ctypes/test_repr.py +++ b/Lib/test/test_ctypes/test_repr.py @@ -1,4 +1,6 @@ -from ctypes import * +from ctypes import (c_byte, c_short, c_int, c_long, c_longlong, + c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong, + c_float, c_double, c_longdouble, c_bool, c_char) import unittest subclasses = [] @@ -25,5 +27,6 @@ def test_char(self): self.assertEqual("c_char(b'x')", repr(c_char(b'x'))) self.assertEqual(" Date: Wed, 14 Jun 2023 05:06:58 +0100 Subject: [PATCH 030/446] GH-89812: Clean up pathlib tests. (#104829) Clean up pathlib tests. Merge `PurePathTest` into `_BasePurePathTest`, and `PathTest` into `_BasePathTest`. --- Lib/test/test_pathlib.py | 180 +++++++++++++++++++++------------------ 1 file changed, 96 insertions(+), 84 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 5963a3d67ff243..46ac30e91e32aa 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -5,6 +5,7 @@ import errno import pathlib import pickle +import posixpath import socket import stat import tempfile @@ -23,20 +24,23 @@ grp = pwd = None -# -# Tests for the pure classes. -# +# Make sure any symbolic links in the base test path are resolved. +BASE = os.path.realpath(TESTFN) +join = lambda *x: os.path.join(BASE, *x) +rel_join = lambda *x: os.path.join(TESTFN, *x) -class _BasePurePathSubclass(object): - def __init__(self, *pathsegments, session_id): - super().__init__(*pathsegments) - self.session_id = session_id +only_nt = unittest.skipIf(os.name != 'nt', + 'test requires a Windows-compatible system') +only_posix = unittest.skipIf(os.name == 'nt', + 'test requires a POSIX-compatible system') - def with_segments(self, *pathsegments): - return type(self)(*pathsegments, session_id=self.session_id) +# +# Tests for the pure classes. +# -class _BasePurePathTest(object): +class PurePathTest(unittest.TestCase): + cls = pathlib.PurePath # Keys are canonical paths, values are list of tuples of arguments # supposed to produce equal paths. @@ -75,6 +79,37 @@ def test_constructor_common(self): self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c"))) self.assertEqual(P(P('./a:b')), P('./a:b')) + def test_concrete_class(self): + if self.cls is pathlib.PurePath: + expected = pathlib.PureWindowsPath if os.name == 'nt' else pathlib.PurePosixPath + else: + expected = self.cls + p = self.cls('a') + self.assertIs(type(p), expected) + + def test_different_flavours_unequal(self): + p = self.cls('a') + if p._flavour is posixpath: + q = pathlib.PureWindowsPath('a') + else: + q = pathlib.PurePosixPath('a') + self.assertNotEqual(p, q) + + def test_different_flavours_unordered(self): + p = self.cls('a') + if p._flavour is posixpath: + q = pathlib.PureWindowsPath('a') + else: + q = pathlib.PurePosixPath('a') + with self.assertRaises(TypeError): + p < q + with self.assertRaises(TypeError): + p <= q + with self.assertRaises(TypeError): + p > q + with self.assertRaises(TypeError): + p >= q + def test_bytes(self): P = self.cls message = (r"argument should be a str or an os\.PathLike object " @@ -122,8 +157,13 @@ def test_str_subclass_common(self): self._check_str_subclass('/a/b.txt') def test_with_segments_common(self): - class P(_BasePurePathSubclass, self.cls): - pass + class P(self.cls): + def __init__(self, *pathsegments, session_id): + super().__init__(*pathsegments) + self.session_id = session_id + + def with_segments(self, *pathsegments): + return type(self)(*pathsegments, session_id=self.session_id) p = P('foo', 'bar', session_id=42) self.assertEqual(42, (p / 'foo').session_id) self.assertEqual(42, ('foo' / p).session_id) @@ -723,7 +763,7 @@ def test_pickling_common(self): self.assertEqual(str(pp), str(p)) -class PurePosixPathTest(_BasePurePathTest, unittest.TestCase): +class PurePosixPathTest(PurePathTest): cls = pathlib.PurePosixPath def test_drive_root_parts(self): @@ -817,10 +857,10 @@ def test_parse_windows_path(self): self.assertEqual(p, pp) -class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase): +class PureWindowsPathTest(PurePathTest): cls = pathlib.PureWindowsPath - equivalences = _BasePurePathTest.equivalences.copy() + equivalences = PurePathTest.equivalences.copy() equivalences.update({ './a:b': [ ('./a:b',) ], 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('.', 'c:', 'a') ], @@ -1491,45 +1531,14 @@ def test_is_reserved(self): self.assertIs(True, P('c:/baz/con/NUL').is_reserved()) self.assertIs(False, P('c:/NUL/con/baz').is_reserved()) -class PurePathTest(_BasePurePathTest, unittest.TestCase): - cls = pathlib.PurePath - - def test_concrete_class(self): - p = self.cls('a') - self.assertIs(type(p), - pathlib.PureWindowsPath if os.name == 'nt' else pathlib.PurePosixPath) - - def test_different_flavours_unequal(self): - p = pathlib.PurePosixPath('a') - q = pathlib.PureWindowsPath('a') - self.assertNotEqual(p, q) - - def test_different_flavours_unordered(self): - p = pathlib.PurePosixPath('a') - q = pathlib.PureWindowsPath('a') - with self.assertRaises(TypeError): - p < q - with self.assertRaises(TypeError): - p <= q - with self.assertRaises(TypeError): - p > q - with self.assertRaises(TypeError): - p >= q - -# -# Tests for the concrete classes. -# +class PurePathSubclassTest(PurePathTest): + class cls(pathlib.PurePath): + pass -# Make sure any symbolic links in the base test path are resolved. -BASE = os.path.realpath(TESTFN) -join = lambda *x: os.path.join(BASE, *x) -rel_join = lambda *x: os.path.join(TESTFN, *x) + # repr() roundtripping is not supported in custom subclass. + test_repr_roundtrips = None -only_nt = unittest.skipIf(os.name != 'nt', - 'test requires a Windows-compatible system') -only_posix = unittest.skipIf(os.name == 'nt', - 'test requires a POSIX-compatible system') @only_posix class PosixPathAsPureTest(PurePosixPathTest): @@ -1550,9 +1559,15 @@ def test_group(self): P('c:/').group() -class _BasePathTest(object): +# +# Tests for the concrete classes. +# + +class PathTest(unittest.TestCase): """Tests for the FS-accessing functionalities of the Path classes.""" + cls = pathlib.Path + # (BASE) # | # |-- brokenLink -> non-existing @@ -1627,6 +1642,20 @@ def assertFileNotFound(self, func, *args, **kwargs): def assertEqualNormCase(self, path_a, path_b): self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b)) + def test_concrete_class(self): + if self.cls is pathlib.Path: + expected = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath + else: + expected = self.cls + p = self.cls('a') + self.assertIs(type(p), expected) + + def test_unsupported_flavour(self): + if self.cls._flavour is os.path: + self.skipTest("path flavour is supported") + else: + self.assertRaises(NotImplementedError, self.cls) + def _test_cwd(self, p): q = self.cls(os.getcwd()) self.assertEqual(p, q) @@ -1683,8 +1712,13 @@ def test_home(self): self._test_home(self.cls.home()) def test_with_segments(self): - class P(_BasePurePathSubclass, self.cls): - pass + class P(self.cls): + def __init__(self, *pathsegments, session_id): + super().__init__(*pathsegments) + self.session_id = session_id + + def with_segments(self, *pathsegments): + return type(self)(*pathsegments, session_id=self.session_id) p = P(BASE, session_id=42) self.assertEqual(42, p.absolute().session_id) self.assertEqual(42, p.resolve().session_id) @@ -1872,6 +1906,11 @@ def _check(glob, expected): else: _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"]) + def test_glob_empty_pattern(self): + p = self.cls() + with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'): + list(p.glob('')) + def test_glob_case_sensitive(self): P = self.cls def _check(path, pattern, case_sensitive, expected): @@ -3022,28 +3061,8 @@ def test_walk_above_recursion_limit(self): list(base.walk(top_down=False)) -class PathTest(_BasePathTest, unittest.TestCase): - cls = pathlib.Path - - def test_concrete_class(self): - p = self.cls('a') - self.assertIs(type(p), - pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath) - - def test_unsupported_flavour(self): - if os.name == 'nt': - self.assertRaises(NotImplementedError, pathlib.PosixPath) - else: - self.assertRaises(NotImplementedError, pathlib.WindowsPath) - - def test_glob_empty_pattern(self): - p = self.cls() - with self.assertRaisesRegex(ValueError, 'Unacceptable pattern'): - list(p.glob('')) - - @only_posix -class PosixPathTest(_BasePathTest, unittest.TestCase): +class PosixPathTest(PathTest): cls = pathlib.PosixPath def test_absolute(self): @@ -3227,7 +3246,7 @@ def test_handling_bad_descriptor(self): @only_nt -class WindowsPathTest(_BasePathTest, unittest.TestCase): +class WindowsPathTest(PathTest): cls = pathlib.WindowsPath def test_absolute(self): @@ -3345,15 +3364,8 @@ def check(): check() -class PurePathSubclassTest(_BasePurePathTest, unittest.TestCase): - class cls(pathlib.PurePath): - pass - - # repr() roundtripping is not supported in custom subclass. - test_repr_roundtrips = None - -class PathSubclassTest(_BasePathTest, unittest.TestCase): +class PathSubclassTest(PathTest): class cls(pathlib.Path): pass From 6199fe3b3236748033a7ce2559aeddb5a91bbbd9 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Wed, 14 Jun 2023 00:33:32 -0400 Subject: [PATCH 031/446] gh-105587: Remove assertion from `_PyStaticObject_CheckRefcnt` (#105638) --- Include/internal/pycore_global_objects_fini_generated.h | 5 ++--- .../2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 546ba6d4c5520f..4b832164766424 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -12,9 +12,8 @@ extern "C" { static inline void _PyStaticObject_CheckRefcnt(PyObject *obj) { if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) { - _PyObject_ASSERT_FAILED_MSG(obj, - "immortal object has less refcnt than expected " - "_Py_IMMORTAL_REFCNT"); + fprintf(stderr, "Immortal Object has less refcnt than expected.\n"); + _PyObject_Dump(obj); } } #endif diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst new file mode 100644 index 00000000000000..488f82c3fb574c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-10-21-38-49.gh-issue-105587.rL3rzv.rst @@ -0,0 +1,3 @@ +The runtime can't guarantee that immortal objects will not be mutated by +Extensions. Thus, this modifies _PyStaticObject_CheckRefcnt to warn +instead of asserting. From 5cdd5ba49db10f05e204e7a49ce184222a93dce8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 14 Jun 2023 00:26:48 -0700 Subject: [PATCH 032/446] tarfile: Fix positional-only syntax in docs (GH-105770) The syntax used in the current docs (a / before any args) is invalid. I think the right approach is for the arguments to arbitrary filter functions to be treated as positional-only, meaning that users can supply filter functions with any names for the argument. tarfile.py only calls the filter function with positional arguments. --- Doc/library/tarfile.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 2f330f018a48be..fd4820e78d68d1 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -908,7 +908,7 @@ can be: path to where the archive is extracted (i.e. the same path is used for all members):: - filter(/, member: TarInfo, path: str) -> TarInfo | None + filter(member: TarInfo, path: str, /) -> TarInfo | None The callable is called just before each member is extracted, so it can take the current state of the disk into account. @@ -928,13 +928,13 @@ Default named filters The pre-defined, named filters are available as functions, so they can be reused in custom filters: -.. function:: fully_trusted_filter(/, member, path) +.. function:: fully_trusted_filter(member, path) Return *member* unchanged. This implements the ``'fully_trusted'`` filter. -.. function:: tar_filter(/, member, path) +.. function:: tar_filter(member, path) Implements the ``'tar'`` filter. @@ -951,7 +951,7 @@ reused in custom filters: Return the modified ``TarInfo`` member. -.. function:: data_filter(/, member, path) +.. function:: data_filter(member, path) Implements the ``'data'`` filter. In addition to what ``tar_filter`` does: From fb655e0c4581ca4bed80db0a083884b29fe142d2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 12:12:25 +0200 Subject: [PATCH 033/446] _ctypes callbacks.c uses _Py_COMP_DIAG_IGNORE_DEPR_DECLS (#105732) Replace #pragma with _Py_COMP_DIAG_PUSH, _Py_COMP_DIAG_IGNORE_DEPR_DECLS and _Py_COMP_DIAG_POP to ease Python maintenance. Also add a comment explaining why callbacks.c ignores a deprecation warning. --- Modules/_ctypes/callbacks.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index d71297f9c5c2f2..0d8ecce009a67a 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -416,25 +416,29 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, PyErr_Format(PyExc_NotImplementedError, "ffi_prep_closure_loc() is missing"); goto error; #else -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif -#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif + // GH-85272, GH-23327, GH-100540: On macOS, + // HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME is checked at runtime because the + // symbol might not be available at runtime when targeting macOS 10.14 + // or earlier. Even if ffi_prep_closure_loc() is called in practice, + // the deprecated ffi_prep_closure() code path is needed if + // HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME is false. + // + // On non-macOS platforms, even if HAVE_FFI_PREP_CLOSURE_LOC_RUNTIME is + // defined as 1 and ffi_prep_closure_loc() is used in practice, this + // code path is still compiled and emits a compiler warning. The + // deprecated code path is likely to be removed by a simple + // optimization pass. + // + // Ignore the compiler warning on the ffi_prep_closure() deprecation, + // rather than using complex #if/#else code paths for the different + // platforms. + _Py_COMP_DIAG_PUSH + _Py_COMP_DIAG_IGNORE_DEPR_DECLS result = ffi_prep_closure(p->pcl_write, &p->cif, closure_fcn, p); - -#if defined(__clang__) - #pragma clang diagnostic pop -#endif -#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))) - #pragma GCC diagnostic pop -#endif - + _Py_COMP_DIAG_POP #endif } + if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_closure failed with %d", result); From 67f69dba0a2adc68c631bad5d970bdd22fc05d91 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 14 Jun 2023 13:26:20 +0300 Subject: [PATCH 034/446] gh-105687: Remove deprecated objects from `re` module (#105688) --- Doc/whatsnew/3.13.rst | 4 +++ Lib/re/__init__.py | 21 +------------ Lib/re/_compiler.py | 2 -- Lib/re/_constants.py | 3 +- Lib/re/_parser.py | 3 +- Lib/test/test_re.py | 30 ++----------------- ...-06-12-15-17-34.gh-issue-105687.ZUonKm.rst | 2 ++ Modules/_sre/sre.c | 1 - Modules/_sre/sre_constants.h | 3 +- 9 files changed, 13 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-12-15-17-34.gh-issue-105687.ZUonKm.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 97bc1587d5052a..78d2a7b6b294d4 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -340,6 +340,10 @@ Removed attribute instead. (Contributed by Nikita Sobolev in :gh:`105546`.) +* Remove undocumented, never working, and deprecated ``re.template`` function + and ``re.TEMPLATE`` flag (and ``re.T`` alias). + (Contributed by Serhiy Storchaka and Nikita Sobolev in :gh:`105687`.) + Porting to Python 3.13 ====================== diff --git a/Lib/re/__init__.py b/Lib/re/__init__.py index 4515650a721ac6..d6fccd5bc97cc0 100644 --- a/Lib/re/__init__.py +++ b/Lib/re/__init__.py @@ -130,7 +130,7 @@ # public symbols __all__ = [ "match", "fullmatch", "search", "sub", "subn", "split", - "findall", "finditer", "compile", "purge", "template", "escape", + "findall", "finditer", "compile", "purge", "escape", "error", "Pattern", "Match", "A", "I", "L", "M", "S", "X", "U", "ASCII", "IGNORECASE", "LOCALE", "MULTILINE", "DOTALL", "VERBOSE", "UNICODE", "NOFLAG", "RegexFlag", @@ -150,7 +150,6 @@ class RegexFlag: DOTALL = S = _compiler.SRE_FLAG_DOTALL # make dot match newline VERBOSE = X = _compiler.SRE_FLAG_VERBOSE # ignore whitespace and comments # sre extensions (experimental, don't rely on these) - TEMPLATE = T = _compiler.SRE_FLAG_TEMPLATE # unknown purpose, deprecated DEBUG = _compiler.SRE_FLAG_DEBUG # dump pattern after compilation __str__ = object.__str__ _numeric_repr_ = hex @@ -233,17 +232,6 @@ def purge(): _cache2.clear() _compile_template.cache_clear() -def template(pattern, flags=0): - "Compile a template pattern, returning a Pattern object, deprecated" - import warnings - warnings.warn("The re.template() function is deprecated " - "as it is an undocumented function " - "without an obvious purpose. " - "Use re.compile() instead.", - DeprecationWarning) - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) # warn just once - return _compile(pattern, flags|T) # SPECIAL_CHARS # closing ')', '}' and ']' @@ -297,13 +285,6 @@ def _compile(pattern, flags): return pattern if not _compiler.isstring(pattern): raise TypeError("first argument must be string or compiled pattern") - if flags & T: - import warnings - warnings.warn("The re.TEMPLATE/re.T flag is deprecated " - "as it is an undocumented flag " - "without an obvious purpose. " - "Don't use it.", - DeprecationWarning) p = _compiler.compile(pattern, flags) if flags & DEBUG: return p diff --git a/Lib/re/_compiler.py b/Lib/re/_compiler.py index d8e0d2fdefdcca..d0a4c55caf6e41 100644 --- a/Lib/re/_compiler.py +++ b/Lib/re/_compiler.py @@ -101,8 +101,6 @@ def _compile(code, pattern, flags): else: emit(ANY) elif op in REPEATING_CODES: - if flags & SRE_FLAG_TEMPLATE: - raise error("internal: unsupported template operator %r" % (op,)) if _simple(av[2]): emit(REPEATING_CODES[op][2]) skip = _len(code); emit(0) diff --git a/Lib/re/_constants.py b/Lib/re/_constants.py index d8718d36075aac..d8e483ac4f23b4 100644 --- a/Lib/re/_constants.py +++ b/Lib/re/_constants.py @@ -13,7 +13,7 @@ # update when constants are added or removed -MAGIC = 20221023 +MAGIC = 20230612 from _sre import MAXREPEAT, MAXGROUPS @@ -204,7 +204,6 @@ def _makecodes(*names): } # flags -SRE_FLAG_TEMPLATE = 1 # template mode (unknown purpose, deprecated) SRE_FLAG_IGNORECASE = 2 # case insensitive SRE_FLAG_LOCALE = 4 # honour system locale SRE_FLAG_MULTILINE = 8 # treat target as multiline string diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 5709acb6267238..6c8a4eccc0e0bb 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -61,12 +61,11 @@ "x": SRE_FLAG_VERBOSE, # extensions "a": SRE_FLAG_ASCII, - "t": SRE_FLAG_TEMPLATE, "u": SRE_FLAG_UNICODE, } TYPE_FLAGS = SRE_FLAG_ASCII | SRE_FLAG_LOCALE | SRE_FLAG_UNICODE -GLOBAL_FLAGS = SRE_FLAG_DEBUG | SRE_FLAG_TEMPLATE +GLOBAL_FLAGS = SRE_FLAG_DEBUG class State: # keeps track of state for parsing diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index d1575dc2c34785..e4d14356402db7 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2398,30 +2398,6 @@ def test_bug_gh91616(self): self.assertTrue(re.fullmatch(r'(?s:(?>.*?\.).*)\Z', "a.txt")) # reproducer self.assertTrue(re.fullmatch(r'(?s:(?=(?P.*?\.))(?P=g0).*)\Z', "a.txt")) - def test_template_function_and_flag_is_deprecated(self): - with self.assertWarns(DeprecationWarning) as cm: - template_re1 = re.template(r'a') - self.assertIn('re.template()', str(cm.warning)) - self.assertIn('is deprecated', str(cm.warning)) - self.assertIn('function', str(cm.warning)) - self.assertNotIn('flag', str(cm.warning)) - - with self.assertWarns(DeprecationWarning) as cm: - # we deliberately use more flags here to test that that still - # triggers the warning - # if paranoid, we could test multiple different combinations, - # but it's probably not worth it - template_re2 = re.compile(r'a', flags=re.TEMPLATE|re.UNICODE) - self.assertIn('re.TEMPLATE', str(cm.warning)) - self.assertIn('is deprecated', str(cm.warning)) - self.assertIn('flag', str(cm.warning)) - self.assertNotIn('function', str(cm.warning)) - - # while deprecated, is should still function - self.assertEqual(template_re1, template_re2) - self.assertTrue(template_re1.match('ahoy')) - self.assertFalse(template_re1.match('nope')) - @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') def test_regression_gh94675(self): pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' @@ -2615,11 +2591,11 @@ def test_flags_repr(self): "re.IGNORECASE|re.DOTALL|re.VERBOSE|0x100000") self.assertEqual( repr(~re.I), - "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DOTALL|re.VERBOSE|re.TEMPLATE|re.DEBUG") + "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DOTALL|re.VERBOSE|re.DEBUG|0x1") self.assertEqual(repr(~(re.I|re.S|re.X)), - "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.TEMPLATE|re.DEBUG") + "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DEBUG|0x1") self.assertEqual(repr(~(re.I|re.S|re.X|(1<<20))), - "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.TEMPLATE|re.DEBUG|0xffe00") + "re.ASCII|re.LOCALE|re.UNICODE|re.MULTILINE|re.DEBUG|0xffe01") class ImplementationTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-06-12-15-17-34.gh-issue-105687.ZUonKm.rst b/Misc/NEWS.d/next/Library/2023-06-12-15-17-34.gh-issue-105687.ZUonKm.rst new file mode 100644 index 00000000000000..7966d3a566414e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-12-15-17-34.gh-issue-105687.ZUonKm.rst @@ -0,0 +1,2 @@ +Remove deprecated ``re.template``, ``re.T``, ``re.TEMPLATE``, +``sre_constans.SRE_FLAG_TEMPLATE``. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index e89e4c77971494..328e4be2fb5e43 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1335,7 +1335,6 @@ pattern_repr(PatternObject *obj) const char *name; int value; } flag_names[] = { - {"re.TEMPLATE", SRE_FLAG_TEMPLATE}, {"re.IGNORECASE", SRE_FLAG_IGNORECASE}, {"re.LOCALE", SRE_FLAG_LOCALE}, {"re.MULTILINE", SRE_FLAG_MULTILINE}, diff --git a/Modules/_sre/sre_constants.h b/Modules/_sre/sre_constants.h index b5692292f65280..bd611b33614509 100644 --- a/Modules/_sre/sre_constants.h +++ b/Modules/_sre/sre_constants.h @@ -11,7 +11,7 @@ * See the sre.c file for information on usage and redistribution. */ -#define SRE_MAGIC 20221023 +#define SRE_MAGIC 20230612 #define SRE_OP_FAILURE 0 #define SRE_OP_SUCCESS 1 #define SRE_OP_ANY 2 @@ -85,7 +85,6 @@ #define SRE_CATEGORY_UNI_NOT_WORD 15 #define SRE_CATEGORY_UNI_LINEBREAK 16 #define SRE_CATEGORY_UNI_NOT_LINEBREAK 17 -#define SRE_FLAG_TEMPLATE 1 #define SRE_FLAG_IGNORECASE 2 #define SRE_FLAG_LOCALE 4 #define SRE_FLAG_MULTILINE 8 From e5d45b7444733861153d6e8959c34323fd361322 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 14 Jun 2023 13:29:16 +0300 Subject: [PATCH 035/446] gh-105745: Fix open method of webbrowser.Konqueror (#105746) --- Lib/webbrowser.py | 9 --------- .../2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 4fc9470051c1ad..8b0628745c57fc 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -390,15 +390,6 @@ def open(self, url, new=0, autoraise=True): return (p.poll() is None) - def open(self, url, new=0, autoraise=True): - sys.audit("webbrowser.open", url) - if new: - ok = self._remote("LOADNEW " + url) - else: - ok = self._remote("LOAD " + url) - return ok - - class Edge(UnixBrowser): "Launcher class for Microsoft Edge browser." diff --git a/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst b/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst new file mode 100644 index 00000000000000..7df7c5a79ec6eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-14-10-27-34.gh-issue-105745.l1ttOQ.rst @@ -0,0 +1 @@ +Fix ``webbrowser.Konqueror.open`` method. From 03160630319ca26dcbbad65225da4248e54c45ec Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 12:30:22 +0200 Subject: [PATCH 036/446] gdb libpython.py: Remove compatibility code (#105739) Remove compatibility code for Python 2 and early Python 3 versions. * Remove os_fsencode() reimplementation: use os.fsencode() directly. os.fsencode() was added to Python 3.2. * Remove references to Python 2 and "Python 3": just say "Python". * Remove outdated u'' string format: use '' instead. --- Tools/gdb/libpython.py | 69 ++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 47 deletions(-) diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 79b8c7527c2307..6225d315281f02 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -111,26 +111,6 @@ def safe_range(val): # threshold in case the data was corrupted return range(safety_limit(int(val))) -try: - os_fsencode = os.fsencode -except AttributeError: - def os_fsencode(filename): - if not isinstance(filename, unicode): - return filename - encoding = sys.getfilesystemencoding() - if encoding == 'mbcs': - # mbcs doesn't support surrogateescape - return filename.encode(encoding) - encoded = [] - for char in filename: - # surrogateescape error handler - if 0xDC80 <= ord(char) <= 0xDCFF: - byte = chr(ord(char) - 0xDC00) - else: - byte = char.encode(encoding) - encoded.append(byte) - return ''.join(encoded) - class StringTruncated(RuntimeError): pass @@ -174,16 +154,12 @@ def __init__(self, gdbval, cast_to=None): def field(self, name): ''' - Get the gdb.Value for the given field within the PyObject, coping with - some python 2 versus python 3 differences. + Get the gdb.Value for the given field within the PyObject. Various libpython types are defined using the "PyObject_HEAD" and "PyObject_VAR_HEAD" macros. - In Python 2, this these are defined so that "ob_type" and (for a var - object) "ob_size" are fields of the type in question. - - In Python 3, this is defined as an embedded PyVarObject type thus: + In Python, this is defined as an embedded PyVarObject type thus: PyVarObject ob_base; so that the "ob_size" field is located insize the "ob_base" field, and the "ob_type" is most easily accessed by casting back to a (PyObject*). @@ -204,8 +180,7 @@ def field(self, name): def pyop_field(self, name): ''' - Get a PyObjectPtr for the given PyObject* field within this PyObject, - coping with some python 2 versus python 3 differences. + Get a PyObjectPtr for the given PyObject* field within this PyObject. ''' return PyObjectPtr.from_pyobject_ptr(self.field(name)) @@ -924,7 +899,7 @@ def proxyval(self, visited): return result def write_repr(self, out, visited): - # Write this out as a Python 3 int literal, i.e. without the "L" suffix + # Write this out as a Python int literal proxy = self.proxyval(visited) out.write("%s" % proxy) @@ -1170,7 +1145,7 @@ def current_line(self): filename = self.filename() try: - with open(os_fsencode(filename), 'r', encoding="utf-8") as fp: + with open(os.fsencode(filename), 'r', encoding="utf-8") as fp: lines = fp.readlines() except IOError: return None @@ -1263,7 +1238,7 @@ def proxyval(self, visited): return set(members) def write_repr(self, out, visited): - # Emulate Python 3's set_repr + # Emulate Python's set_repr tp_name = self.safe_tp_name() # Guard against infinite loops: @@ -1272,13 +1247,13 @@ def write_repr(self, out, visited): return visited.add(self.as_address()) - # Python 3's set_repr special-cases the empty set: + # Python's set_repr special-cases the empty set: if not self.field('used'): out.write(tp_name) out.write('()') return - # Python 3 uses {} for set literals: + # Python uses {} for set literals: if tp_name != 'set': out.write(tp_name) out.write('(') @@ -1309,13 +1284,13 @@ def proxyval(self, visited): return str(self) def write_repr(self, out, visited): - # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix + # Write this out as a Python bytes literal, i.e. with a "b" prefix - # Get a PyStringObject* within the Python 2 gdb process: + # Get a PyStringObject* within the Python gdb process: proxy = self.proxyval(visited) - # Transliteration of Python 3's Objects/bytesobject.c:PyBytes_Repr - # to Python 2 code: + # Transliteration of Python's Objects/bytesobject.c:PyBytes_Repr + # to Python code: quote = "'" if "'" in proxy and not '"' in proxy: quote = '"' @@ -1380,7 +1355,7 @@ class PyTypeObjectPtr(PyObjectPtr): def _unichr_is_printable(char): - # Logic adapted from Python 3's Tools/unicode/makeunicodedata.py + # Logic adapted from Python's Tools/unicode/makeunicodedata.py if char == u" ": return True import unicodedata @@ -1416,17 +1391,17 @@ def proxyval(self, visited): # Convert the int code points to unicode characters, and generate a # local unicode instance. - result = u''.join(map(chr, code_points)) + result = ''.join(map(chr, code_points)) return result def write_repr(self, out, visited): - # Write this out as a Python 3 str literal, i.e. without a "u" prefix + # Write this out as a Python str literal - # Get a PyUnicodeObject* within the Python 2 gdb process: + # Get a PyUnicodeObject* within the Python gdb process: proxy = self.proxyval(visited) - # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr - # to Python 2: + # Transliteration of Python's Object/unicodeobject.c:unicode_repr + # to Python: if "'" in proxy and '"' not in proxy: quote = '"' else: @@ -1477,7 +1452,7 @@ def write_repr(self, out, visited): # (categories Z* and C* except ASCII space) if not printable: if ch2 is not None: - # Match Python 3's representation of non-printable + # Match Python's representation of non-printable # wide characters. code = (ord(ch) & 0x03FF) << 10 code |= ord(ch2) & 0x03FF @@ -1608,8 +1583,8 @@ def pretty_printer_lookup(gdbval): if the code is autoloaded by gdb when visiting libpython.so, provided that this python file is installed to the same path as the library (or its .debug file) plus a "-gdb.py" suffix, e.g: - /usr/lib/libpython2.6.so.1.0-gdb.py - /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py + /usr/lib/libpython3.12.so.1.0-gdb.py + /usr/lib/debug/usr/lib/libpython3.12.so.1.0.debug-gdb.py """ def register (obj): if obj is None: @@ -1928,7 +1903,7 @@ def invoke(self, args, from_tty): start = 1 try: - f = open(os_fsencode(filename), 'r', encoding="utf-8") + f = open(os.fsencode(filename), 'r', encoding="utf-8") except IOError as err: sys.stdout.write('Unable to open %s: %s\n' % (filename, err)) From ba516e70c6d156dc59dede35b6fc3db0151780a5 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Wed, 14 Jun 2023 15:17:12 +0300 Subject: [PATCH 037/446] gh-102541: Hide traceback in help prompt (gh-102614) --- Lib/pydoc.py | 21 ++++++++++++------- ...-03-12-01-17-15.gh-issue-102541.LK1adc.rst | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 84e673a7f87f90..d69369d4196eaa 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1780,10 +1780,15 @@ def render_doc(thing, title='Python Library Documentation: %s', forceload=0, return title % desc + '\n\n' + renderer.document(object, name) def doc(thing, title='Python Library Documentation: %s', forceload=0, - output=None): + output=None, is_cli=False): """Display text documentation, given an object or a path to an object.""" if output is None: - pager(render_doc(thing, title, forceload)) + try: + pager(render_doc(thing, title, forceload)) + except ImportError as exc: + if is_cli: + raise + print(exc) else: output.write(render_doc(thing, title, forceload, plaintext)) @@ -2044,7 +2049,7 @@ def getline(self, prompt): self.output.flush() return self.input.readline() - def help(self, request): + def help(self, request, is_cli=False): if isinstance(request, str): request = request.strip() if request == 'keywords': self.listkeywords() @@ -2056,13 +2061,13 @@ def help(self, request): elif request in self.symbols: self.showsymbol(request) elif request in ['True', 'False', 'None']: # special case these keywords since they are objects too - doc(eval(request), 'Help on %s:') + doc(eval(request), 'Help on %s:', is_cli=is_cli) elif request in self.keywords: self.showtopic(request) elif request in self.topics: self.showtopic(request) - elif request: doc(request, 'Help on %s:', output=self._output) - else: doc(str, 'Help on %s:', output=self._output) + elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) + else: doc(str, 'Help on %s:', output=self._output, is_cli=is_cli) elif isinstance(request, Helper): self() - else: doc(request, 'Help on %s:', output=self._output) + else: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli) self.output.write('\n') def intro(self): @@ -2800,7 +2805,7 @@ class BadUsage(Exception): pass else: writedoc(arg) else: - help.help(arg) + help.help(arg, is_cli=True) except (ImportError, ErrorDuringImport) as value: print(value) sys.exit(1) diff --git a/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst b/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst new file mode 100644 index 00000000000000..45b10679e19e2d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-12-01-17-15.gh-issue-102541.LK1adc.rst @@ -0,0 +1 @@ +Hide traceback in :func:`help` prompt, when import failed. From fc8037d84c5f886849a05ec993dd0f79a356d372 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 14 Jun 2023 05:35:06 -0700 Subject: [PATCH 038/446] gh-104873: Add typing.get_protocol_members and typing.is_protocol (#104878) Co-authored-by: Alex Waygood --- Doc/library/typing.rst | 32 +++++++++ Doc/whatsnew/3.13.rst | 8 +++ Lib/test/test_typing.py | 69 ++++++++++++++++++- Lib/typing.py | 42 +++++++++++ ...-05-24-09-55-33.gh-issue-104873.BKQ54y.rst | 3 + 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-24-09-55-33.gh-issue-104873.BKQ54y.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 949b108c60c4f6..487be8f28a788d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3388,6 +3388,38 @@ Introspection helpers .. versionadded:: 3.8 +.. function:: get_protocol_members(tp) + + Return the set of members defined in a :class:`Protocol`. + + :: + + >>> from typing import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) + + Raise :exc:`TypeError` for arguments that are not Protocols. + + .. versionadded:: 3.13 + +.. function:: is_protocol(tp) + + Determine if a type is a :class:`Protocol`. + + For example:: + + class P(Protocol): + def a(self) -> str: ... + b: int + + is_protocol(P) # => True + is_protocol(int) # => False + + .. versionadded:: 3.13 + .. function:: is_typeddict(tp) Check if a type is a :class:`TypedDict`. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 78d2a7b6b294d4..fcd10e522c8aca 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -120,6 +120,14 @@ traceback to format the nested exceptions of a :exc:`BaseExceptionGroup` instance, recursively. (Contributed by Irit Katriel in :gh:`105292`.) +typing +------ + +* Add :func:`typing.get_protocol_members` to return the set of members + defining a :class:`typing.Protocol`. Add :func:`typing.is_protocol` to + check whether a class is a :class:`typing.Protocol`. (Contributed by Jelle Zijlstra in + :gh:`104873`.) + Optimizations ============= diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 432fc88b1c072e..a36d801c52514b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -24,9 +24,9 @@ from typing import Generic, ClassVar, Final, final, Protocol from typing import assert_type, cast, runtime_checkable from typing import get_type_hints -from typing import get_origin, get_args +from typing import get_origin, get_args, get_protocol_members from typing import override -from typing import is_typeddict +from typing import is_typeddict, is_protocol from typing import reveal_type from typing import dataclass_transform from typing import no_type_check, no_type_check_decorator @@ -3363,6 +3363,18 @@ def meth(self): pass self.assertNotIn("__callable_proto_members_only__", vars(NonP)) self.assertNotIn("__callable_proto_members_only__", vars(NonPR)) + self.assertEqual(get_protocol_members(P), {"x"}) + self.assertEqual(get_protocol_members(PR), {"meth"}) + + # the returned object should be immutable, + # and should be a different object to the original attribute + # to prevent users from (accidentally or deliberately) + # mutating the attribute on the original class + self.assertIsInstance(get_protocol_members(P), frozenset) + self.assertIsNot(get_protocol_members(P), P.__protocol_attrs__) + self.assertIsInstance(get_protocol_members(PR), frozenset) + self.assertIsNot(get_protocol_members(PR), P.__protocol_attrs__) + acceptable_extra_attrs = { '_is_protocol', '_is_runtime_protocol', '__parameters__', '__init__', '__annotations__', '__subclasshook__', @@ -3778,6 +3790,59 @@ def __init__(self): Foo() # Previously triggered RecursionError + def test_get_protocol_members(self): + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(object) + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(object()) + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(Protocol) + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(Generic) + + class P(Protocol): + a: int + def b(self) -> str: ... + @property + def c(self) -> int: ... + + self.assertEqual(get_protocol_members(P), {'a', 'b', 'c'}) + self.assertIsInstance(get_protocol_members(P), frozenset) + self.assertIsNot(get_protocol_members(P), P.__protocol_attrs__) + + class Concrete: + a: int + def b(self) -> str: return "capybara" + @property + def c(self) -> int: return 5 + + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(Concrete) + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(Concrete()) + + class ConcreteInherit(P): + a: int = 42 + def b(self) -> str: return "capybara" + @property + def c(self) -> int: return 5 + + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(ConcreteInherit) + with self.assertRaisesRegex(TypeError, "not a Protocol"): + get_protocol_members(ConcreteInherit()) + + def test_is_protocol(self): + self.assertTrue(is_protocol(Proto)) + self.assertTrue(is_protocol(Point)) + self.assertFalse(is_protocol(Concrete)) + self.assertFalse(is_protocol(Concrete())) + self.assertFalse(is_protocol(Generic)) + self.assertFalse(is_protocol(object)) + + # Protocol is not itself a protocol + self.assertFalse(is_protocol(Protocol)) + def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta(self): # Ensure the cache is empty, or this test won't work correctly collections.abc.Sized._abc_registry_clear() diff --git a/Lib/typing.py b/Lib/typing.py index a531e7d7abbef6..4e6dc44773538e 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -131,7 +131,9 @@ 'get_args', 'get_origin', 'get_overloads', + 'get_protocol_members', 'get_type_hints', + 'is_protocol', 'is_typeddict', 'LiteralString', 'Never', @@ -3337,3 +3339,43 @@ def method(self) -> None: # read-only property, TypeError if it's a builtin class. pass return method + + +def is_protocol(tp: type, /) -> bool: + """Return True if the given type is a Protocol. + + Example:: + + >>> from typing import Protocol, is_protocol + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> is_protocol(P) + True + >>> is_protocol(int) + False + """ + return ( + isinstance(tp, type) + and getattr(tp, '_is_protocol', False) + and tp != Protocol + ) + + +def get_protocol_members(tp: type, /) -> frozenset[str]: + """Return the set of members defined in a Protocol. + + Example:: + + >>> from typing import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) + + Raise a TypeError for arguments that are not Protocols. + """ + if not is_protocol(tp): + raise TypeError(f'{tp!r} is not a Protocol') + return frozenset(tp.__protocol_attrs__) diff --git a/Misc/NEWS.d/next/Library/2023-05-24-09-55-33.gh-issue-104873.BKQ54y.rst b/Misc/NEWS.d/next/Library/2023-05-24-09-55-33.gh-issue-104873.BKQ54y.rst new file mode 100644 index 00000000000000..c901d83812f176 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-24-09-55-33.gh-issue-104873.BKQ54y.rst @@ -0,0 +1,3 @@ +Add :func:`typing.get_protocol_members` to return the set of members +defining a :class:`typing.Protocol`. Add :func:`typing.is_protocol` to +check whether a class is a :class:`typing.Protocol`. Patch by Jelle Zijlstra. From ad56340b665c5d8ac1f318964f71697bba41acb7 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 14 Jun 2023 13:38:49 +0100 Subject: [PATCH 039/446] gh-105566: Deprecate unusual ways of creating `typing.NamedTuple` classes (#105609) Deprecate creating a typing.NamedTuple class using keyword arguments to denote the fields (`NT = NamedTuple("NT", x=int, y=str)`). This will be disallowed in Python 3.15. Use the class-based syntax or the functional syntax instead. Two methods of creating `NamedTuple` classes with 0 fields using the functional syntax are also deprecated, and will be disallowed in Python 3.15: `NT = NamedTuple("NT")` and `NT = NamedTuple("NT", None)`. To create a `NamedTuple` class with 0 fields, either use `class NT(NamedTuple): pass` or `NT = NamedTuple("NT", [])`. --- Doc/library/typing.rst | 13 +++ Doc/whatsnew/3.13.rst | 11 +++ Lib/test/test_typing.py | 83 +++++++++++++++++-- Lib/typing.py | 48 ++++++++++- ...-06-09-20-34-23.gh-issue-105566.YxlGg1.rst | 10 +++ 5 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-09-20-34-23.gh-issue-105566.YxlGg1.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 487be8f28a788d..aedef091e44c00 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2038,6 +2038,19 @@ These are not used in annotations. They are building blocks for declaring types. .. versionchanged:: 3.11 Added support for generic namedtuples. + .. deprecated-removed:: 3.13 3.15 + The undocumented keyword argument syntax for creating NamedTuple classes + (``NT = NamedTuple("NT", x=int)``) is deprecated, and will be disallowed + in 3.15. Use the class-based syntax or the functional syntax instead. + + .. deprecated-removed:: 3.13 3.15 + When using the functional syntax to create a NamedTuple class, failing to + pass a value to the 'fields' parameter (``NT = NamedTuple("NT")``) is + deprecated. Passing ``None`` to the 'fields' parameter + (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be + disallowed in Python 3.15. To create a NamedTuple class with 0 fields, + use ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. + .. class:: NewType(name, tp) Helper class to create low-overhead :ref:`distinct types `. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index fcd10e522c8aca..cf7c2ca24429d6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -141,6 +141,17 @@ Deprecated methods of the :class:`wave.Wave_read` and :class:`wave.Wave_write` classes. They will be removed in Python 3.15. (Contributed by Victor Stinner in :gh:`105096`.) +* Creating a :class:`typing.NamedTuple` class using keyword arguments to denote + the fields (``NT = NamedTuple("NT", x=int, y=int)``) is deprecated, and will + be disallowed in Python 3.15. Use the class-based syntax or the functional + syntax instead. (Contributed by Alex Waygood in :gh:`105566`.) +* When using the functional syntax to create a :class:`typing.NamedTuple` + class, failing to pass a value to the 'fields' parameter + (``NT = NamedTuple("NT")``) is deprecated. Passing ``None`` to the 'fields' + parameter (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be + disallowed in Python 3.15. To create a NamedTuple class with 0 fields, use + ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. + (Contributed by Alex Waygood in :gh:`105566`.) * :mod:`array`'s ``'u'`` format code, deprecated in docs since Python 3.3, emits :exc:`DeprecationWarning` since 3.13 diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a36d801c52514b..92f38043af5c03 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7189,18 +7189,47 @@ class Group(NamedTuple): self.assertEqual(a, (1, [2])) def test_namedtuple_keyword_usage(self): - LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) + with self.assertWarnsRegex( + DeprecationWarning, + "Creating NamedTuple classes using keyword arguments is deprecated" + ): + LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int) + nick = LocalEmployee('Nick', 25) self.assertIsInstance(nick, tuple) self.assertEqual(nick.name, 'Nick') self.assertEqual(LocalEmployee.__name__, 'LocalEmployee') self.assertEqual(LocalEmployee._fields, ('name', 'age')) self.assertEqual(LocalEmployee.__annotations__, dict(name=str, age=int)) - with self.assertRaises(TypeError): + + with self.assertRaisesRegex( + TypeError, + "Either list of fields or keywords can be provided to NamedTuple, not both" + ): NamedTuple('Name', [('x', int)], y=str) + with self.assertRaisesRegex( + TypeError, + "Either list of fields or keywords can be provided to NamedTuple, not both" + ): + NamedTuple('Name', [], y=str) + + with self.assertRaisesRegex( + TypeError, + ( + r"Cannot pass `None` as the 'fields' parameter " + r"and also specify fields using keyword arguments" + ) + ): + NamedTuple('Name', None, x=int) + def test_namedtuple_special_keyword_names(self): - NT = NamedTuple("NT", cls=type, self=object, typename=str, fields=list) + with self.assertWarnsRegex( + DeprecationWarning, + "Creating NamedTuple classes using keyword arguments is deprecated" + ): + NT = NamedTuple("NT", cls=type, self=object, typename=str, fields=list) + self.assertEqual(NT.__name__, 'NT') self.assertEqual(NT._fields, ('cls', 'self', 'typename', 'fields')) a = NT(cls=str, self=42, typename='foo', fields=[('bar', tuple)]) @@ -7210,12 +7239,32 @@ def test_namedtuple_special_keyword_names(self): self.assertEqual(a.fields, [('bar', tuple)]) def test_empty_namedtuple(self): - NT = NamedTuple('NT') + expected_warning = re.escape( + "Failing to pass a value for the 'fields' parameter is deprecated " + "and will be disallowed in Python 3.15. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. `NT1 = NamedTuple('NT1', [])`." + ) + with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): + NT1 = NamedTuple('NT1') + + expected_warning = re.escape( + "Passing `None` as the 'fields' parameter is deprecated " + "and will be disallowed in Python 3.15. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. `NT2 = NamedTuple('NT2', [])`." + ) + with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): + NT2 = NamedTuple('NT2', None) + + NT3 = NamedTuple('NT2', []) class CNT(NamedTuple): pass # empty body - for struct in [NT, CNT]: + for struct in NT1, NT2, NT3, CNT: with self.subTest(struct=struct): self.assertEqual(struct._fields, ()) self.assertEqual(struct._field_defaults, {}) @@ -7225,13 +7274,29 @@ class CNT(NamedTuple): def test_namedtuple_errors(self): with self.assertRaises(TypeError): NamedTuple.__new__() - with self.assertRaises(TypeError): + + with self.assertRaisesRegex( + TypeError, + "missing 1 required positional argument" + ): NamedTuple() - with self.assertRaises(TypeError): + + with self.assertRaisesRegex( + TypeError, + "takes from 1 to 2 positional arguments but 3 were given" + ): NamedTuple('Emp', [('name', str)], None) - with self.assertRaises(ValueError): + + with self.assertRaisesRegex( + ValueError, + "Field names cannot start with an underscore" + ): NamedTuple('Emp', [('_name', str)]) - with self.assertRaises(TypeError): + + with self.assertRaisesRegex( + TypeError, + "missing 1 required positional argument: 'typename'" + ): NamedTuple(typename='Emp', name=str, id=int) def test_copy_and_pickle(self): diff --git a/Lib/typing.py b/Lib/typing.py index 4e6dc44773538e..570cb80cfeeb2c 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2755,7 +2755,16 @@ def __new__(cls, typename, bases, ns): return nm_tpl -def NamedTuple(typename, fields=None, /, **kwargs): +class _Sentinel: + __slots__ = () + def __repr__(self): + return '' + + +_sentinel = _Sentinel() + + +def NamedTuple(typename, fields=_sentinel, /, **kwargs): """Typed version of namedtuple. Usage:: @@ -2775,11 +2784,44 @@ class Employee(NamedTuple): Employee = NamedTuple('Employee', [('name', str), ('id', int)]) """ - if fields is None: - fields = kwargs.items() + if fields is _sentinel: + if kwargs: + deprecated_thing = "Creating NamedTuple classes using keyword arguments" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "Use the class-based or functional syntax instead." + ) + else: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif fields is None: + if kwargs: + raise TypeError( + "Cannot pass `None` as the 'fields' parameter " + "and also specify fields using keyword arguments" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." elif kwargs: raise TypeError("Either list of fields or keywords" " can be provided to NamedTuple, not both") + if fields is _sentinel or fields is None: + import warnings + warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15)) + fields = kwargs.items() nt = _make_nmtuple(typename, fields, module=_caller()) nt.__orig_bases__ = (NamedTuple,) return nt diff --git a/Misc/NEWS.d/next/Library/2023-06-09-20-34-23.gh-issue-105566.YxlGg1.rst b/Misc/NEWS.d/next/Library/2023-06-09-20-34-23.gh-issue-105566.YxlGg1.rst new file mode 100644 index 00000000000000..c2c497aee513d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-09-20-34-23.gh-issue-105566.YxlGg1.rst @@ -0,0 +1,10 @@ +Deprecate creating a :class:`typing.NamedTuple` class using keyword +arguments to denote the fields (``NT = NamedTuple("NT", x=int, y=str)``). +This will be disallowed in Python 3.15. +Use the class-based syntax or the functional syntax instead. + +Two methods of creating ``NamedTuple`` classes with 0 fields using the +functional syntax are also deprecated, and will be disallowed in Python 3.15: +``NT = NamedTuple("NT")`` and ``NT = NamedTuple("NT", None)``. To create a +``NamedTuple`` class with 0 fields, either use ``class NT(NamedTuple): pass`` or +``NT = NamedTuple("NT", [])``. From 7199584ac8632eab57612f595a7162ab8d2ebbc0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 14 Jun 2023 13:46:37 +0100 Subject: [PATCH 040/446] GH-100987: Allow objects other than code objects as the "executable" of an internal frame. (GH-105727) * Add table describing possible executable classes for out-of-process debuggers. * Remove shim code object creation code as it is no longer needed. * Make lltrace a bit more robust w.r.t. non-standard frames. --- Include/internal/pycore_code.h | 13 - Include/internal/pycore_frame.h | 30 +- .../pycore_global_objects_fini_generated.h | 1 - Include/internal/pycore_global_strings.h | 1 - Include/internal/pycore_interp.h | 1 - .../internal/pycore_runtime_init_generated.h | 1 - ...-06-09-10-48-17.gh-issue-100987.mK-xny.rst | 4 + Objects/codeobject.c | 73 -- Objects/frameobject.c | 39 +- Objects/genobject.c | 6 +- Objects/typeobject.c | 4 +- Python/_warnings.c | 2 +- Python/bytecodes.c | 29 +- Python/ceval.c | 37 +- Python/ceval_macros.h | 12 +- Python/frame.c | 22 +- Python/generated_cases.c.h | 791 +++++++++--------- Python/instrumentation.c | 10 +- Python/intrinsics.c | 6 +- Python/legacy_tracing.c | 3 +- Python/optimizer.c | 8 +- Python/perf_trampoline.c | 2 +- Python/pylifecycle.c | 20 - Python/pystate.c | 1 - Python/traceback.c | 4 +- Python/tracemalloc.c | 3 +- Tools/c-analyzer/cpython/ignored.tsv | 1 + Tools/gdb/libpython.py | 25 +- 28 files changed, 542 insertions(+), 607 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-10-48-17.gh-issue-100987.mK-xny.rst diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index ef940b54b2b086..8755cb371a87c4 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -447,19 +447,6 @@ adaptive_counter_backoff(uint16_t counter) { return adaptive_counter_bits(value, backoff); } - -/* Line array cache for tracing */ - -typedef struct _PyShimCodeDef { - const uint8_t *code; - int codelen; - int stacksize; - const char *cname; -} _PyShimCodeDef; - -extern PyCodeObject * -_Py_MakeShimCode(const _PyShimCodeDef *code); - extern uint32_t _Py_next_func_version; diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index a72e03f1438fc8..caff86c64acfe2 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -47,7 +47,7 @@ enum _frameowner { }; typedef struct _PyInterpreterFrame { - PyCodeObject *f_code; /* Strong reference */ + PyObject *f_executable; /* Strong reference */ struct _PyInterpreterFrame *previous; PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ @@ -73,20 +73,25 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) + ((int)((IF)->prev_instr - _PyCode_CODE(_PyFrame_GetCode(IF)))) + +static inline PyCodeObject *_PyFrame_GetCode(_PyInterpreterFrame *f) { + assert(PyCode_Check(f->f_executable)); + return (PyCodeObject *)f->f_executable; +} static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { - return f->localsplus + f->f_code->co_nlocalsplus; + return f->localsplus + _PyFrame_GetCode(f)->co_nlocalsplus; } static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) { - assert(f->stacktop > f->f_code->co_nlocalsplus); + assert(f->stacktop > _PyFrame_GetCode(f)->co_nlocalsplus); 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_GetCode(f)->co_nlocalsplus); f->stacktop--; return f->localsplus[f->stacktop]; } @@ -119,7 +124,7 @@ _PyFrame_Initialize( PyObject *locals, PyCodeObject *code, int null_locals_from) { frame->f_funcobj = (PyObject *)func; - frame->f_code = (PyCodeObject *)Py_NewRef(code); + frame->f_executable = Py_NewRef(code); frame->f_builtins = func->func_builtins; frame->f_globals = func->func_globals; frame->f_locals = locals; @@ -172,8 +177,11 @@ _PyFrame_SetStackPointer(_PyInterpreterFrame *frame, PyObject **stack_pointer) static inline bool _PyFrame_IsIncomplete(_PyInterpreterFrame *frame) { + if (frame->owner == FRAME_OWNED_BY_CSTACK) { + return true; + } return frame->owner != FRAME_OWNED_BY_GENERATOR && - frame->prev_instr < _PyCode_CODE(frame->f_code) + frame->f_code->_co_firsttraceable; + frame->prev_instr < _PyCode_CODE(_PyFrame_GetCode(frame)) + _PyFrame_GetCode(frame)->_co_firsttraceable; } static inline _PyInterpreterFrame * @@ -272,6 +280,14 @@ PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) return (PyGenObject *)(((char *)frame) - offset_in_gen); } +#define PY_EXECUTABLE_KIND_SKIP 0 +#define PY_EXECUTABLE_KIND_PY_FUNCTION 1 +#define PY_EXECUTABLE_KIND_BUILTIN_FUNCTION 3 +#define PY_EXECUTABLE_KIND_METHOD_DESCRIPTOR 4 +#define PY_EXECUTABLE_KINDS 5 + +PyAPI_DATA(const PyTypeObject *) const PyUnstable_ExecutableKinds[PY_EXECUTABLE_KINDS+1]; + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4b832164766424..f85207b4bde292 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -565,7 +565,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(newline)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(open_br)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(percent)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(shim_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(type_params)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_STR(utf_8)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(CANCELLED)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 088bd96c756b49..3c9c12202ba1b9 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -51,7 +51,6 @@ struct _Py_global_strings { STRUCT_FOR_STR(newline, "\n") STRUCT_FOR_STR(open_br, "{") STRUCT_FOR_STR(percent, "%") - STRUCT_FOR_STR(shim_name, "") STRUCT_FOR_STR(type_params, ".type_params") STRUCT_FOR_STR(utf_8, "utf-8") } literals; diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index a6f4677920ab7e..a4177f379acc68 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -159,7 +159,6 @@ struct _is { struct ast_state ast; struct types_state types; struct callable_cache callable_cache; - PyCodeObject *interpreter_trampoline; _PyOptimizerObject *optimizer; uint16_t optimizer_resume_threshold; uint16_t optimizer_backedge_threshold; diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 2963423f607108..9a28368a124ce8 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -557,7 +557,6 @@ extern "C" { INIT_STR(newline, "\n"), \ INIT_STR(open_br, "{"), \ INIT_STR(percent, "%"), \ - INIT_STR(shim_name, ""), \ INIT_STR(type_params, ".type_params"), \ INIT_STR(utf_8, "utf-8"), \ } diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-10-48-17.gh-issue-100987.mK-xny.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-10-48-17.gh-issue-100987.mK-xny.rst new file mode 100644 index 00000000000000..e25789e711c35d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-10-48-17.gh-issue-100987.mK-xny.rst @@ -0,0 +1,4 @@ +Allow objects other than code objects as the "executable" in internal +frames. In the long term, this can help tools like Cython and PySpy interact +more efficiently. In the shorter term, it allows us to perform some +optimizations more simply. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index cf087e8d3fbeb9..377cac55848fbd 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2316,76 +2316,3 @@ _PyStaticCode_Init(PyCodeObject *co) } #define MAX_CODE_UNITS_PER_LOC_ENTRY 8 - -PyCodeObject * -_Py_MakeShimCode(const _PyShimCodeDef *codedef) -{ - PyObject *name = NULL; - PyObject *co_code = NULL; - PyObject *lines = NULL; - PyCodeObject *codeobj = NULL; - uint8_t *loc_table = NULL; - - name = _PyUnicode_FromASCII(codedef->cname, strlen(codedef->cname)); - if (name == NULL) { - goto cleanup; - } - co_code = PyBytes_FromStringAndSize( - (const char *)codedef->code, codedef->codelen); - if (co_code == NULL) { - goto cleanup; - } - int code_units = codedef->codelen / sizeof(_Py_CODEUNIT); - int loc_entries = (code_units + MAX_CODE_UNITS_PER_LOC_ENTRY - 1) / - MAX_CODE_UNITS_PER_LOC_ENTRY; - loc_table = PyMem_Malloc(loc_entries); - if (loc_table == NULL) { - PyErr_NoMemory(); - goto cleanup; - } - for (int i = 0; i < loc_entries-1; i++) { - loc_table[i] = 0x80 | (PY_CODE_LOCATION_INFO_NONE << 3) | 7; - code_units -= MAX_CODE_UNITS_PER_LOC_ENTRY; - } - assert(loc_entries > 0); - assert(code_units > 0 && code_units <= MAX_CODE_UNITS_PER_LOC_ENTRY); - loc_table[loc_entries-1] = 0x80 | - (PY_CODE_LOCATION_INFO_NONE << 3) | (code_units-1); - lines = PyBytes_FromStringAndSize((const char *)loc_table, loc_entries); - PyMem_Free(loc_table); - if (lines == NULL) { - goto cleanup; - } - _Py_DECLARE_STR(shim_name, ""); - struct _PyCodeConstructor con = { - .filename = &_Py_STR(shim_name), - .name = name, - .qualname = name, - .flags = CO_NEWLOCALS | CO_OPTIMIZED, - - .code = co_code, - .firstlineno = 1, - .linetable = lines, - - .consts = (PyObject *)&_Py_SINGLETON(tuple_empty), - .names = (PyObject *)&_Py_SINGLETON(tuple_empty), - - .localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty), - .localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty), - - .argcount = 0, - .posonlyargcount = 0, - .kwonlyargcount = 0, - - .stacksize = codedef->stacksize, - - .exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty), - }; - - codeobj = _PyCode_New(&con); -cleanup: - Py_XDECREF(name); - Py_XDECREF(co_code); - Py_XDECREF(lines); - return codeobj; -} diff --git a/Objects/frameobject.c b/Objects/frameobject.c index f2061e6a18fa40..98f4a0378bf76d 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -642,6 +642,7 @@ _PyFrame_GetState(PyFrameObject *frame) static int frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignored)) { + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); if (p_new_lineno == NULL) { PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); return -1; @@ -719,7 +720,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore } new_lineno = (int)l_new_lineno; - if (new_lineno < f->f_frame->f_code->co_firstlineno) { + if (new_lineno < code->co_firstlineno) { PyErr_Format(PyExc_ValueError, "line %d comes before the current code block", new_lineno); @@ -728,8 +729,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore /* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this * should never overflow. */ - int len = (int)Py_SIZE(f->f_frame->f_code); - int *lines = marklines(f->f_frame->f_code, len); + int len = (int)Py_SIZE(code); + int *lines = marklines(code, len); if (lines == NULL) { return -1; } @@ -743,7 +744,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore return -1; } - int64_t *stacks = mark_stacks(f->f_frame->f_code, len); + int64_t *stacks = mark_stacks(code, len); if (stacks == NULL) { PyMem_Free(lines); return -1; @@ -788,7 +789,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore // in the new location. Rather than crashing or changing co_code, just bind // None instead: int unbound = 0; - for (int i = 0; i < f->f_frame->f_code->co_nlocalsplus; i++) { + for (int i = 0; i < code->co_nlocalsplus; i++) { // Counting every unbound local is overly-cautious, but a full flow // analysis (like we do in the compiler) is probably too expensive: unbound += f->f_frame->localsplus[i] == NULL; @@ -801,7 +802,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore } // Do this in a second pass to avoid writing a bunch of Nones when // warnings are being treated as errors and the previous bit raises: - for (int i = 0; i < f->f_frame->f_code->co_nlocalsplus; i++) { + for (int i = 0; i < code->co_nlocalsplus; i++) { if (f->f_frame->localsplus[i] == NULL) { f->f_frame->localsplus[i] = Py_NewRef(Py_None); unbound--; @@ -832,7 +833,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore } /* Finally set the new lasti and return OK. */ f->f_lineno = 0; - f->f_frame->prev_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr; + f->f_frame->prev_instr = _PyCode_CODE(code) + best_addr; return 0; } @@ -886,15 +887,15 @@ frame_dealloc(PyFrameObject *f) } Py_TRASHCAN_BEGIN(f, frame_dealloc); - PyCodeObject *co = NULL; + PyObject *co = NULL; /* Kill all local variables including specials, if we own them */ if (f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT) { assert(f->f_frame == (_PyInterpreterFrame *)f->_f_frame_data); _PyInterpreterFrame *frame = (_PyInterpreterFrame *)f->_f_frame_data; /* Don't clear code object until the end */ - co = frame->f_code; - frame->f_code = NULL; + co = frame->f_executable; + frame->f_executable = NULL; Py_CLEAR(frame->f_funcobj); Py_CLEAR(frame->f_locals); PyObject **locals = _PyFrame_GetLocalsArray(frame); @@ -968,7 +969,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) { Py_ssize_t res; res = offsetof(PyFrameObject, _f_frame_data) + offsetof(_PyInterpreterFrame, localsplus); - PyCodeObject *code = f->f_frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *); return PyLong_FromSsize_t(res); } @@ -980,7 +981,7 @@ static PyObject * frame_repr(PyFrameObject *f) { int lineno = PyFrame_GetLineNumber(f); - PyCodeObject *code = f->f_frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); return PyUnicode_FromFormat( "", f, code->co_filename, lineno, code->co_name); @@ -1102,7 +1103,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg) // This only works when opcode is a non-quickened form: assert(_PyOpcode_Deopt[opcode] == opcode); int check_oparg = 0; - for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code); + for (_Py_CODEUNIT *instruction = _PyCode_CODE(_PyFrame_GetCode(frame)); instruction < frame->prev_instr; instruction++) { int check_opcode = _PyOpcode_Deopt[instruction->op.code]; @@ -1128,7 +1129,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame) { // COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt // here: - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); int lasti = _PyInterpreterFrame_LASTI(frame); if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS && PyFunction_Check(frame->f_funcobj))) @@ -1145,7 +1146,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame) frame->localsplus[offset + i] = Py_NewRef(o); } // COPY_FREE_VARS doesn't have inline CACHEs, either: - frame->prev_instr = _PyCode_CODE(frame->f_code); + frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)); } @@ -1213,7 +1214,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) frame_init_get_vars(frame); - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); for (int i = 0; i < co->co_nlocalsplus; i++) { PyObject *value; // borrowed reference if (!frame_get_var(frame, co, i, &value)) { @@ -1257,7 +1258,7 @@ PyFrame_GetVar(PyFrameObject *frame_obj, PyObject *name) _PyInterpreterFrame *frame = frame_obj->f_frame; frame_init_get_vars(frame); - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); for (int i = 0; i < co->co_nlocalsplus; i++) { PyObject *var_name = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (!_PyUnicode_Equal(var_name, name)) { @@ -1331,7 +1332,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) return; } fast = _PyFrame_GetLocalsArray(frame); - co = frame->f_code; + co = _PyFrame_GetCode(frame); PyObject *exc = PyErr_GetRaisedException(); for (int i = 0; i < co->co_nlocalsplus; i++) { @@ -1417,7 +1418,7 @@ PyFrame_GetCode(PyFrameObject *frame) { assert(frame != NULL); assert(!_PyFrame_IsIncomplete(frame->f_frame)); - PyCodeObject *code = frame->f_frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame->f_frame); assert(code != NULL); return (PyCodeObject*)Py_NewRef(code); } diff --git a/Objects/genobject.c b/Objects/genobject.c index 5c93ef49583b1e..6f0f02c9a16e5e 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -29,7 +29,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG = static inline PyCodeObject * _PyGen_GetCode(PyGenObject *gen) { _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); - return frame->f_code; + return _PyFrame_GetCode(frame); } PyCodeObject * @@ -957,7 +957,7 @@ static PyObject * gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, PyObject *name, PyObject *qualname) { - PyCodeObject *code = f->f_frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(f->f_frame); int size = code->co_nlocalsplus + code->co_stacksize; PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); if (gen == NULL) { @@ -1339,7 +1339,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) } frame = current_frame; for (int i = 0; i < frame_count; ++i) { - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); int line = PyUnstable_InterpreterFrame_GetLine(frame); PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, code->co_name); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1e0d79bc126452..5d29d262575315 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10405,7 +10405,7 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co, return -1; } - assert(cframe->f_code->co_nlocalsplus > 0); + assert(_PyFrame_GetCode(cframe)->co_nlocalsplus > 0); PyObject *firstarg = _PyFrame_GetLocalsArray(cframe)[0]; // The first argument might be a cell. if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) { @@ -10498,7 +10498,7 @@ super_init_impl(PyObject *self, PyTypeObject *type, PyObject *obj) { "super(): no current frame"); return -1; } - int res = super_init_without_args(frame, frame->f_code, &type, &obj); + int res = super_init_without_args(frame, _PyFrame_GetCode(frame), &type, &obj); if (res < 0) { return -1; diff --git a/Python/_warnings.c b/Python/_warnings.c index 465cbf9bd3039a..e4941f7b068d3f 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -898,7 +898,7 @@ setup_context(Py_ssize_t stack_level, } else { globals = f->f_frame->f_globals; - *filename = Py_NewRef(f->f_frame->f_code->co_filename); + *filename = Py_NewRef(_PyFrame_GetCode(f->f_frame)->co_filename); *lineno = PyFrame_GetLineNumber(f); Py_DECREF(f); } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2d9671f27edfe8..78e276bfad20e7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -137,8 +137,8 @@ dummy_func( assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ - if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { - int err = _Py_Instrument(frame->f_code, tstate->interp); + if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) { + int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); ERROR_IF(err, error); next_instr--; } @@ -152,8 +152,8 @@ dummy_func( * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? */ - if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { - if (_Py_Instrument(frame->f_code, tstate->interp)) { + if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) { + if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) { goto error; } next_instr--; @@ -666,8 +666,6 @@ dummy_func( inst(INTERPRETER_EXIT, (retval --)) { assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); - STACK_SHRINK(1); // Since we're not going to DISPATCH() - assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); @@ -971,7 +969,7 @@ dummy_func( if (oparg) { PyObject *lasti = values[0]; if (PyLong_Check(lasti)) { - frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); + frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { @@ -1385,7 +1383,7 @@ dummy_func( // Can't use ERROR_IF here. // Fortunately we don't need its superpower. if (oldobj == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); goto error; } PyCell_SET(cell, NULL); @@ -1395,8 +1393,8 @@ dummy_func( inst(LOAD_FROM_DICT_OR_DEREF, (class_dict -- value)) { PyObject *name; assert(class_dict); - assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); - name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); + assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); + name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); if (PyDict_CheckExact(class_dict)) { value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { @@ -1422,7 +1420,7 @@ dummy_func( PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); goto error; } Py_INCREF(value); @@ -1433,7 +1431,7 @@ dummy_func( PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); ERROR_IF(true, error); } Py_INCREF(value); @@ -1448,7 +1446,7 @@ dummy_func( inst(COPY_FREE_VARS, (--)) { /* Copy closure variables to free variables */ - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; assert(oparg == co->co_nfreevars); @@ -2175,7 +2173,8 @@ dummy_func( }; inst(ENTER_EXECUTOR, (--)) { - _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; + PyCodeObject *code = _PyFrame_GetCode(frame); + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { @@ -2292,7 +2291,7 @@ dummy_func( /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ - if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { + if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ _PyErr_SetString(tstate, PyExc_TypeError, diff --git a/Python/ceval.c b/Python/ceval.c index b91f94d2873963..54ef03702f7006 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -129,6 +129,9 @@ lltrace_instruction(_PyInterpreterFrame *frame, PyObject **stack_pointer, _Py_CODEUNIT *next_instr) { + if (frame->owner == FRAME_OWNED_BY_CSTACK) { + return; + } /* This dump_stack() operation is risky, since the repr() of some objects enters the interpreter recursively. It is also slow. So you might want to comment it out. */ @@ -137,7 +140,7 @@ lltrace_instruction(_PyInterpreterFrame *frame, int opcode = next_instr->op.code; const char *opname = _PyOpcode_OpName[opcode]; assert(opname != NULL); - int offset = (int)(next_instr - _PyCode_CODE(frame->f_code)); + int offset = (int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame))); if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) { printf("%d: %s %d\n", offset * 2, opname, oparg); } @@ -150,7 +153,7 @@ static void lltrace_resume_frame(_PyInterpreterFrame *frame) { PyObject *fobj = frame->f_funcobj; - if (frame->owner == FRAME_OWNED_BY_CSTACK || + if (!PyCode_Check(frame->f_executable) || fobj == NULL || !PyFunction_Check(fobj) ) { @@ -621,6 +624,13 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { tstate->py_recursion_remaining++; } +static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { + /* Put a NOP at the start, so that the IP points into + * the code, rather than before it */ + { .op.code = NOP, .op.arg = 0 }, + { .op.code = INTERPRETER_EXIT, .op.arg = 0 }, + { .op.code = RESUME, .op.arg = 0 } +}; /* Disable unused label warnings. They are handy for debugging, even if computed gotos aren't used. */ @@ -668,7 +678,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int cframe.previous = prev_cframe; tstate->cframe = &cframe; - assert(tstate->interp->interpreter_trampoline != NULL); #ifdef Py_DEBUG /* Set these to invalid but identifiable values for debugging. */ entry_frame.f_funcobj = (PyObject*)0xaaa0; @@ -677,9 +686,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int entry_frame.f_globals = (PyObject*)0xaaa3; entry_frame.f_builtins = (PyObject*)0xaaa4; #endif - entry_frame.f_code = tstate->interp->interpreter_trampoline; - entry_frame.prev_instr = - _PyCode_CODE(tstate->interp->interpreter_trampoline); + entry_frame.f_executable = Py_None; + entry_frame.prev_instr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS; entry_frame.stacktop = 0; entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.return_offset = 0; @@ -701,7 +709,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } /* Because this avoids the RESUME, * we need to update instrumentation */ - _Py_Instrument(frame->f_code, tstate->interp); + _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); monitor_throw(tstate, frame, frame->prev_instr); /* TO DO -- Monitor throw entry. */ goto resume_with_error; @@ -715,7 +723,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* Sets the above local variables from the frame */ #define SET_LOCALS_FROM_FRAME() \ - assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ next_instr = frame->prev_instr + 1; \ stack_pointer = _PyFrame_GetStackPointer(frame); @@ -874,7 +881,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int opcode = next_instr->op.code; _PyErr_Format(tstate, PyExc_SystemError, "%U:%d: unknown opcode %d", - frame->f_code->co_filename, + _PyFrame_GetCode(frame)->co_filename, PyUnstable_InterpreterFrame_GetLine(frame), opcode); goto error; @@ -889,7 +896,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int { format_exc_check_arg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, - PyTuple_GetItem(frame->f_code->co_localsplusnames, oparg) + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) ); goto error; } @@ -929,7 +936,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* We can't use frame->f_lasti here, as RERAISE may have set it */ int offset = INSTR_OFFSET()-1; int level, handler, lasti; - if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) { + if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) { // No handlers, so exit. assert(_PyErr_Occurred(tstate)); @@ -1523,12 +1530,12 @@ clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) assert(frame->owner == FRAME_OWNED_BY_THREAD); // Make sure that this is, indeed, the top frame. We can't check this in // _PyThreadState_PopFrame, since f_code is already cleared at that point: - assert((PyObject **)frame + frame->f_code->co_framesize == + assert((PyObject **)frame + _PyFrame_GetCode(frame)->co_framesize == tstate->datastack_top); tstate->c_recursion_remaining--; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame); _PyFrame_ClearExceptCode(frame); - Py_DECREF(frame->f_code); + Py_DECREF(frame->f_executable); tstate->c_recursion_remaining++; _PyThreadState_PopFrame(tstate, frame); } @@ -2013,7 +2020,7 @@ do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame, static inline int no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event) { - _PyCoMonitoringData *data = frame->f_code->_co_monitoring; + _PyCoMonitoringData *data = _PyFrame_GetCode(frame)->_co_monitoring; if (data) { if (data->active_monitors.tools[event] == 0) { return 1; @@ -2331,7 +2338,7 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf) int result = cf->cf_flags != 0; if (current_frame != NULL) { - const int codeflags = current_frame->f_code->co_flags; + const int codeflags = _PyFrame_GetCode(current_frame)->co_flags; const int compilerflags = codeflags & PyCF_MASK; if (compilerflags) { result = 1; diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 6f6fabc37efd6a..1130b10ef7638b 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -138,13 +138,13 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* Code access macros */ /* The integer overflow is checked by an assertion below. */ -#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) +#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame)))) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = word.op.code; \ oparg = word.op.arg; \ } while (0) -#define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x)) +#define JUMPTO(x) (next_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + (x)) #define JUMPBY(x) (next_instr += (x)) /* OpCode prediction macros @@ -182,7 +182,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) -#define STACK_SIZE() (frame->f_code->co_stacksize) +#define STACK_SIZE() (_PyFrame_GetCode(frame)->co_stacksize) #define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) @@ -221,8 +221,8 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* Data access macros */ -#define FRAME_CO_CONSTS (frame->f_code->co_consts) -#define FRAME_CO_NAMES (frame->f_code->co_names) +#define FRAME_CO_CONSTS (_PyFrame_GetCode(frame)->co_consts) +#define FRAME_CO_NAMES (_PyFrame_GetCode(frame)->co_names) /* Local variable macros */ @@ -270,6 +270,8 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define GLOBALS() frame->f_globals #define BUILTINS() frame->f_builtins #define LOCALS() frame->f_locals +#define CONSTS() _PyFrame_GetCode(frame)->co_consts +#define NAMES() _PyFrame_GetCode(frame)->co_names #define DTRACE_FUNCTION_ENTRY() \ if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \ diff --git a/Python/frame.c b/Python/frame.c index b84fd9b6a9380a..581e4f95710fe2 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -14,7 +14,7 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg) Py_VISIT(frame->frame_obj); Py_VISIT(frame->f_locals); Py_VISIT(frame->f_funcobj); - Py_VISIT(frame->f_code); + Py_VISIT(_PyFrame_GetCode(frame)); /* locals */ PyObject **locals = _PyFrame_GetLocalsArray(frame); int i = 0; @@ -31,7 +31,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) assert(frame->frame_obj == NULL); PyObject *exc = PyErr_GetRaisedException(); - PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code); + PyFrameObject *f = _PyFrame_New_NoTrack(_PyFrame_GetCode(frame)); if (f == NULL) { Py_XDECREF(exc); return NULL; @@ -65,7 +65,7 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) { - assert(src->stacktop >= src->f_code->co_nlocalsplus); + assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus); Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; memcpy(dest, src, size); // Don't leave a dangling pointer to the old frame when creating generators @@ -81,7 +81,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); assert(frame->owner != FRAME_CLEARED); Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; - Py_INCREF(frame->f_code); + Py_INCREF(_PyFrame_GetCode(frame)); memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); frame = (_PyInterpreterFrame *)f->_f_frame_data; f->f_frame = frame; @@ -89,7 +89,7 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) if (_PyFrame_IsIncomplete(frame)) { // This may be a newly-created generator or coroutine frame. Since it's // dead anyways, just pretend that the first RESUME ran: - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; } assert(!_PyFrame_IsIncomplete(frame)); @@ -149,7 +149,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) PyObject * PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) { - PyObject *code = (PyObject *)frame->f_code; + PyObject *code = frame->f_executable; Py_INCREF(code); return code; } @@ -164,5 +164,13 @@ int PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame) { int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - return PyCode_Addr2Line(frame->f_code, addr); + return PyCode_Addr2Line(_PyFrame_GetCode(frame), addr); } + +const PyTypeObject *const PyUnstable_ExecutableKinds[PY_EXECUTABLE_KINDS+1] = { + [PY_EXECUTABLE_KIND_SKIP] = &_PyNone_Type, + [PY_EXECUTABLE_KIND_PY_FUNCTION] = &PyCode_Type, + [PY_EXECUTABLE_KIND_BUILTIN_FUNCTION] = &PyMethod_Type, + [PY_EXECUTABLE_KIND_METHOD_DESCRIPTOR] = &PyMethodDescr_Type, + [PY_EXECUTABLE_KINDS] = NULL, +}; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ef4c921f19a6f8..008524ac95b69b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -12,8 +12,8 @@ assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ - if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { - int err = _Py_Instrument(frame->f_code, tstate->interp); + if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) { + int err = _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); if (err) goto error; next_instr--; } @@ -30,8 +30,8 @@ * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? */ - if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) { - if (_Py_Instrument(frame->f_code, tstate->interp)) { + if (_PyFrame_GetCode(frame)->_co_instrumentation_version != tstate->interp->monitoring_version) { + if (_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp)) { goto error; } next_instr--; @@ -935,20 +935,18 @@ #line 667 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); - STACK_SHRINK(1); // Since we're not going to DISPATCH() - assert(EMPTY()); /* Restore previous cframe and return. */ tstate->cframe = cframe.previous; assert(tstate->cframe->current_frame == frame->previous); assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 947 "Python/generated_cases.c.h" + #line 945 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 680 "Python/bytecodes.c" + #line 678 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -961,12 +959,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 965 "Python/generated_cases.c.h" + #line 963 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 695 "Python/bytecodes.c" + #line 693 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -983,11 +981,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 987 "Python/generated_cases.c.h" + #line 985 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 714 "Python/bytecodes.c" + #line 712 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1001,11 +999,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1005 "Python/generated_cases.c.h" + #line 1003 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 730 "Python/bytecodes.c" + #line 728 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1023,13 +1021,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1027 "Python/generated_cases.c.h" + #line 1025 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 750 "Python/bytecodes.c" + #line 748 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1042,16 +1040,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1046 "Python/generated_cases.c.h" + #line 1044 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 763 "Python/bytecodes.c" + #line 761 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1053 "Python/generated_cases.c.h" + #line 1051 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 768 "Python/bytecodes.c" + #line 766 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1064,7 +1062,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1068 "Python/generated_cases.c.h" + #line 1066 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1072,7 +1070,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 783 "Python/bytecodes.c" + #line 781 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1115,7 +1113,7 @@ Py_DECREF(next_iter); } } - #line 1119 "Python/generated_cases.c.h" + #line 1117 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; DISPATCH(); @@ -1124,16 +1122,16 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 828 "Python/bytecodes.c" + #line 826 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1135 "Python/generated_cases.c.h" + #line 1133 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 835 "Python/bytecodes.c" + #line 833 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1150,7 +1148,7 @@ } if (iter == NULL) goto pop_1_error; - #line 1154 "Python/generated_cases.c.h" + #line 1152 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1161,7 +1159,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 859 "Python/bytecodes.c" + #line 857 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1208,7 +1206,7 @@ } } Py_DECREF(v); - #line 1212 "Python/generated_cases.c.h" + #line 1210 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1217,7 +1215,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 908 "Python/bytecodes.c" + #line 906 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1233,12 +1231,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1237 "Python/generated_cases.c.h" + #line 1235 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 926 "Python/bytecodes.c" + #line 924 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1256,12 +1254,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1260 "Python/generated_cases.c.h" + #line 1258 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 946 "Python/bytecodes.c" + #line 944 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1278,15 +1276,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1282 "Python/generated_cases.c.h" + #line 1280 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 965 "Python/bytecodes.c" + #line 963 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1290 "Python/generated_cases.c.h" + #line 1288 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1294,12 +1292,12 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 970 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; if (PyLong_Check(lasti)) { - frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); + frame->prev_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { @@ -1312,26 +1310,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1316 "Python/generated_cases.c.h" + #line 1314 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 990 "Python/bytecodes.c" + #line 988 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1325 "Python/generated_cases.c.h" + #line 1323 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 993 "Python/bytecodes.c" + #line 991 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1335 "Python/generated_cases.c.h" + #line 1333 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1342,23 +1340,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1002 "Python/bytecodes.c" + #line 1000 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1351 "Python/generated_cases.c.h" + #line 1349 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1007 "Python/bytecodes.c" + #line 1005 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1362 "Python/generated_cases.c.h" + #line 1360 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1367,9 +1365,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1016 "Python/bytecodes.c" + #line 1014 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1373 "Python/generated_cases.c.h" + #line 1371 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1377,7 +1375,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1020 "Python/bytecodes.c" + #line 1018 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1399,7 +1397,7 @@ if (true) goto error; } } - #line 1403 "Python/generated_cases.c.h" + #line 1401 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1407,33 +1405,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1045 "Python/bytecodes.c" + #line 1043 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1418 "Python/generated_cases.c.h" + #line 1416 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1052 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1427 "Python/generated_cases.c.h" + #line 1425 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1059 "Python/bytecodes.c" + #line 1057 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1431 "Python/generated_cases.c.h" + #line 1429 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1063 "Python/bytecodes.c" + #line 1061 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1450,7 +1448,7 @@ name); goto error; } - #line 1454 "Python/generated_cases.c.h" + #line 1452 "Python/generated_cases.c.h" DISPATCH(); } @@ -1458,7 +1456,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1089 "Python/bytecodes.c" + #line 1087 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1471,11 +1469,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1475 "Python/generated_cases.c.h" + #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1102 "Python/bytecodes.c" + #line 1100 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1479 "Python/generated_cases.c.h" + #line 1477 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1485,14 +1483,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1106 "Python/bytecodes.c" + #line 1104 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1496 "Python/generated_cases.c.h" + #line 1494 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1503,7 +1501,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1116 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1511,7 +1509,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1515 "Python/generated_cases.c.h" + #line 1513 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1522,7 +1520,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1127 "Python/bytecodes.c" + #line 1125 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1530,7 +1528,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1534 "Python/generated_cases.c.h" + #line 1532 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1540,15 +1538,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1138 "Python/bytecodes.c" + #line 1136 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1548 "Python/generated_cases.c.h" + #line 1546 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1142 "Python/bytecodes.c" + #line 1140 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1552 "Python/generated_cases.c.h" + #line 1550 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1559,7 +1557,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1153 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1575,12 +1573,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1579 "Python/generated_cases.c.h" + #line 1577 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1169 "Python/bytecodes.c" + #line 1167 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1584 "Python/generated_cases.c.h" + #line 1582 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1588,34 +1586,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1173 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1595 "Python/generated_cases.c.h" + #line 1593 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1176 "Python/bytecodes.c" + #line 1174 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1599 "Python/generated_cases.c.h" + #line 1597 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1180 "Python/bytecodes.c" + #line 1178 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1609 "Python/generated_cases.c.h" + #line 1607 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1183 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1613 "Python/generated_cases.c.h" + #line 1611 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1187 "Python/bytecodes.c" + #line 1185 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1627,7 +1625,7 @@ } goto error; } - #line 1631 "Python/generated_cases.c.h" + #line 1629 "Python/generated_cases.c.h" DISPATCH(); } @@ -1635,7 +1633,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1201 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1643,7 +1641,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1647 "Python/generated_cases.c.h" + #line 1645 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1655,7 +1653,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1201 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1663,13 +1661,13 @@ if (true) goto error; } Py_INCREF(locals); - #line 1667 "Python/generated_cases.c.h" + #line 1665 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1213 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1726,7 +1724,7 @@ } } } - #line 1730 "Python/generated_cases.c.h" + #line 1728 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1739,7 +1737,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1213 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1796,7 +1794,7 @@ } } } - #line 1800 "Python/generated_cases.c.h" + #line 1798 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1808,7 +1806,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1282 "Python/bytecodes.c" + #line 1280 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1860,7 +1858,7 @@ } } null = NULL; - #line 1864 "Python/generated_cases.c.h" + #line 1862 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1874,7 +1872,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1336 "Python/bytecodes.c" + #line 1334 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1885,7 +1883,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1889 "Python/generated_cases.c.h" + #line 1887 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1900,7 +1898,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1349 "Python/bytecodes.c" + #line 1347 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1915,7 +1913,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1919 "Python/generated_cases.c.h" + #line 1917 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1925,16 +1923,16 @@ } TARGET(DELETE_FAST) { - #line 1366 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1933 "Python/generated_cases.c.h" + #line 1931 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1372 "Python/bytecodes.c" + #line 1370 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1943,34 +1941,34 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1947 "Python/generated_cases.c.h" + #line 1945 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1383 "Python/bytecodes.c" + #line 1381 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. // Fortunately we don't need its superpower. if (oldobj == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); goto error; } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1963 "Python/generated_cases.c.h" + #line 1961 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1396 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" PyObject *name; assert(class_dict); - assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); - name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); + assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); + name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); if (PyDict_CheckExact(class_dict)) { value = PyDict_GetItemWithError(class_dict, name); if (value != NULL) { @@ -1996,27 +1994,27 @@ PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); goto error; } Py_INCREF(value); } - #line 2005 "Python/generated_cases.c.h" + #line 2003 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1433 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); if (true) goto error; } Py_INCREF(value); - #line 2020 "Python/generated_cases.c.h" + #line 2018 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2024,20 +2022,20 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1443 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2033 "Python/generated_cases.c.h" + #line 2031 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1450 "Python/bytecodes.c" + #line 1448 "Python/bytecodes.c" /* Copy closure variables to free variables */ - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; assert(oparg == co->co_nfreevars); @@ -2046,22 +2044,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2050 "Python/generated_cases.c.h" + #line 2048 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1463 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2059 "Python/generated_cases.c.h" + #line 2057 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1465 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2065 "Python/generated_cases.c.h" + #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2071,10 +2069,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1469 "Python/bytecodes.c" + #line 1467 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2078 "Python/generated_cases.c.h" + #line 2076 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2084,10 +2082,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1474 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2091 "Python/generated_cases.c.h" + #line 2089 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2097,7 +2095,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1479 "Python/bytecodes.c" + #line 1477 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2108,13 +2106,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2112 "Python/generated_cases.c.h" + #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1490 "Python/bytecodes.c" + #line 1488 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2118 "Python/generated_cases.c.h" + #line 2116 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2123,13 +2121,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1497 "Python/bytecodes.c" + #line 1495 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2129 "Python/generated_cases.c.h" + #line 2127 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1499 "Python/bytecodes.c" + #line 1497 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2133 "Python/generated_cases.c.h" + #line 2131 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2137,7 +2135,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1503 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2152,7 +2150,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2156 "Python/generated_cases.c.h" + #line 2154 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2162,7 +2160,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1520 "Python/bytecodes.c" + #line 1518 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2170,13 +2168,13 @@ if (map == NULL) goto error; - #line 2174 "Python/generated_cases.c.h" + #line 2172 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1528 "Python/bytecodes.c" + #line 1526 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2180 "Python/generated_cases.c.h" + #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2184,7 +2182,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1532 "Python/bytecodes.c" + #line 1530 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2224,7 +2222,7 @@ Py_DECREF(ann_dict); } } - #line 2228 "Python/generated_cases.c.h" + #line 2226 "Python/generated_cases.c.h" DISPATCH(); } @@ -2232,7 +2230,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1574 "Python/bytecodes.c" + #line 1572 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2242,14 +2240,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2246 "Python/generated_cases.c.h" + #line 2244 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1584 "Python/bytecodes.c" + #line 1582 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2253 "Python/generated_cases.c.h" + #line 2251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2257,7 +2255,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1588 "Python/bytecodes.c" + #line 1586 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2265,12 +2263,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2269 "Python/generated_cases.c.h" + #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1596 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2274 "Python/generated_cases.c.h" + #line 2272 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2278,17 +2276,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1602 "Python/bytecodes.c" + #line 1600 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2287 "Python/generated_cases.c.h" + #line 2285 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1607 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2292 "Python/generated_cases.c.h" + #line 2290 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2297,25 +2295,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1613 "Python/bytecodes.c" + #line 1611 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2307 "Python/generated_cases.c.h" + #line 2305 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1621 "Python/bytecodes.c" + #line 1619 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2319 "Python/generated_cases.c.h" + #line 2317 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2326,7 +2324,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1635 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2368,16 +2366,16 @@ } } } - #line 2372 "Python/generated_cases.c.h" + #line 2370 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1677 "Python/bytecodes.c" + #line 1675 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2381 "Python/generated_cases.c.h" + #line 2379 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2392,20 +2390,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1696 "Python/bytecodes.c" + #line 1694 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2403 "Python/generated_cases.c.h" + #line 2401 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1703 "Python/bytecodes.c" + #line 1701 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2409 "Python/generated_cases.c.h" + #line 2407 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2420,7 +2418,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1707 "Python/bytecodes.c" + #line 1705 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2443,7 +2441,7 @@ res = res2; res2 = NULL; } - #line 2447 "Python/generated_cases.c.h" + #line 2445 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2457,7 +2455,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1746 "Python/bytecodes.c" + #line 1744 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2491,9 +2489,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2495 "Python/generated_cases.c.h" + #line 2493 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1780 "Python/bytecodes.c" + #line 1778 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2502,12 +2500,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2506 "Python/generated_cases.c.h" + #line 2504 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1789 "Python/bytecodes.c" + #line 1787 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2511 "Python/generated_cases.c.h" + #line 2509 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2521,7 +2519,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1798 "Python/bytecodes.c" + #line 1796 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2534,7 +2532,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2538 "Python/generated_cases.c.h" + #line 2536 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2549,7 +2547,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1814 "Python/bytecodes.c" + #line 1812 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2562,7 +2560,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2566 "Python/generated_cases.c.h" + #line 2564 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2577,7 +2575,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1830 "Python/bytecodes.c" + #line 1828 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2604,7 +2602,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2608 "Python/generated_cases.c.h" + #line 2606 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2619,7 +2617,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1860 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2629,7 +2627,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2633 "Python/generated_cases.c.h" + #line 2631 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2644,7 +2642,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1873 "Python/bytecodes.c" + #line 1871 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2656,7 +2654,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2660 "Python/generated_cases.c.h" + #line 2658 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2670,7 +2668,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1888 "Python/bytecodes.c" + #line 1886 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2694,7 +2692,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2698 "Python/generated_cases.c.h" + #line 2696 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2702,7 +2700,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1914 "Python/bytecodes.c" + #line 1912 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2728,7 +2726,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2732 "Python/generated_cases.c.h" + #line 2730 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2736,7 +2734,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1942 "Python/bytecodes.c" + #line 1940 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2754,7 +2752,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2758 "Python/generated_cases.c.h" + #line 2756 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2765,7 +2763,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1962 "Python/bytecodes.c" + #line 1960 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2804,7 +2802,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2808 "Python/generated_cases.c.h" + #line 2806 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2815,7 +2813,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2003 "Python/bytecodes.c" + #line 2001 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2825,7 +2823,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2829 "Python/generated_cases.c.h" + #line 2827 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2837,7 +2835,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2022 "Python/bytecodes.c" + #line 2020 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2850,12 +2848,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2854 "Python/generated_cases.c.h" + #line 2852 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2035 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2859 "Python/generated_cases.c.h" + #line 2857 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2866,7 +2864,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2039 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2877,7 +2875,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2881 "Python/generated_cases.c.h" + #line 2879 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2888,7 +2886,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2053 "Python/bytecodes.c" + #line 2051 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2903,7 +2901,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2907 "Python/generated_cases.c.h" + #line 2905 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2914,7 +2912,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2071 "Python/bytecodes.c" + #line 2069 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2926,7 +2924,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2930 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2937,14 +2935,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2085 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2943 "Python/generated_cases.c.h" + #line 2941 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2087 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2948 "Python/generated_cases.c.h" + #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2954,15 +2952,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2091 "Python/bytecodes.c" + #line 2089 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2960 "Python/generated_cases.c.h" + #line 2958 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2093 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2966 "Python/generated_cases.c.h" + #line 2964 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2973,12 +2971,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2098 "Python/bytecodes.c" + #line 2096 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2979 "Python/generated_cases.c.h" + #line 2977 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2100 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2986,10 +2984,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2990 "Python/generated_cases.c.h" + #line 2988 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2108 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2998,7 +2996,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3002 "Python/generated_cases.c.h" + #line 3000 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3008,21 +3006,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2119 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3015 "Python/generated_cases.c.h" + #line 3013 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2122 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3022 "Python/generated_cases.c.h" + #line 3020 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2127 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3026 "Python/generated_cases.c.h" + #line 3024 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3031,15 +3029,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2131 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3038 "Python/generated_cases.c.h" + #line 3036 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2134 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3043 "Python/generated_cases.c.h" + #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3048,25 +3046,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2138 "Python/bytecodes.c" + #line 2136 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3056 "Python/generated_cases.c.h" + #line 3054 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2144 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" JUMPBY(oparg); - #line 3065 "Python/generated_cases.c.h" + #line 3063 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2148 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3083,14 +3081,15 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3087 "Python/generated_cases.c.h" + #line 3085 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2178 "Python/bytecodes.c" - _PyExecutorObject *executor = (_PyExecutorObject *)frame->f_code->co_executors->executors[oparg]; + #line 2176 "Python/bytecodes.c" + PyCodeObject *code = _PyFrame_GetCode(frame); + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { @@ -3098,20 +3097,20 @@ goto error; } goto resume_frame; - #line 3102 "Python/generated_cases.c.h" + #line 3101 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2189 "Python/bytecodes.c" + #line 2188 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3113 "Python/generated_cases.c.h" + #line 3112 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2195 "Python/bytecodes.c" + #line 2194 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3119,22 +3118,22 @@ if (err < 0) goto pop_1_error; } } - #line 3123 "Python/generated_cases.c.h" + #line 3122 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2205 "Python/bytecodes.c" + #line 2204 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3136 "Python/generated_cases.c.h" + #line 3135 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2211 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3142,63 +3141,63 @@ if (err < 0) goto pop_1_error; } } - #line 3146 "Python/generated_cases.c.h" + #line 3145 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2221 "Python/bytecodes.c" + #line 2220 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3155 "Python/generated_cases.c.h" + #line 3154 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2223 "Python/bytecodes.c" + #line 2222 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3160 "Python/generated_cases.c.h" + #line 3159 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2228 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3172 "Python/generated_cases.c.h" + #line 3171 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2233 "Python/bytecodes.c" + #line 2232 "Python/bytecodes.c" } - #line 3176 "Python/generated_cases.c.h" + #line 3175 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2237 "Python/bytecodes.c" + #line 2236 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3189 "Python/generated_cases.c.h" + #line 3188 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2246 "Python/bytecodes.c" + #line 2245 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3202 "Python/generated_cases.c.h" + #line 3201 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3209,16 +3208,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2254 "Python/bytecodes.c" + #line 2253 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3218 "Python/generated_cases.c.h" + #line 3217 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2259 "Python/bytecodes.c" + #line 2258 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3226,7 +3225,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3230 "Python/generated_cases.c.h" + #line 3229 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3235,10 +3234,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2269 "Python/bytecodes.c" + #line 2268 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3242 "Python/generated_cases.c.h" + #line 3241 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3247,10 +3246,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2274 "Python/bytecodes.c" + #line 2273 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3254 "Python/generated_cases.c.h" + #line 3253 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3260,11 +3259,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2279 "Python/bytecodes.c" + #line 2278 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3268 "Python/generated_cases.c.h" + #line 3267 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3273,14 +3272,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2285 "Python/bytecodes.c" + #line 2284 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3280 "Python/generated_cases.c.h" + #line 3279 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2288 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3284 "Python/generated_cases.c.h" + #line 3283 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3288,11 +3287,11 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2292 "Python/bytecodes.c" + #line 2291 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ - if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { + if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { /* and it is used in a 'yield from' expression of a regular generator. */ _PyErr_SetString(tstate, PyExc_TypeError, @@ -3311,11 +3310,11 @@ if (iter == NULL) { goto error; } - #line 3315 "Python/generated_cases.c.h" + #line 3314 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2315 "Python/bytecodes.c" + #line 2314 "Python/bytecodes.c" } - #line 3319 "Python/generated_cases.c.h" + #line 3318 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3325,7 +3324,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2333 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3356,7 +3355,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3360 "Python/generated_cases.c.h" + #line 3359 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3364,7 +3363,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2366 "Python/bytecodes.c" + #line 2365 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3390,14 +3389,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3394 "Python/generated_cases.c.h" + #line 3393 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2394 "Python/bytecodes.c" + #line 2393 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3417,7 +3416,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3421 "Python/generated_cases.c.h" + #line 3420 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3427,7 +3426,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2416 "Python/bytecodes.c" + #line 2415 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3447,7 +3446,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3451 "Python/generated_cases.c.h" + #line 3450 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3457,7 +3456,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2438 "Python/bytecodes.c" + #line 2437 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3475,7 +3474,7 @@ if (next == NULL) { goto error; } - #line 3479 "Python/generated_cases.c.h" + #line 3478 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3484,7 +3483,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2458 "Python/bytecodes.c" + #line 2457 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3500,14 +3499,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3504 "Python/generated_cases.c.h" + #line 3503 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2476 "Python/bytecodes.c" + #line 2475 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3530,16 +3529,16 @@ Py_DECREF(enter); goto error; } - #line 3534 "Python/generated_cases.c.h" + #line 3533 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2499 "Python/bytecodes.c" + #line 2498 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3543 "Python/generated_cases.c.h" + #line 3542 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3550,7 +3549,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2508 "Python/bytecodes.c" + #line 2507 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3576,16 +3575,16 @@ Py_DECREF(enter); goto error; } - #line 3580 "Python/generated_cases.c.h" + #line 3579 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2534 "Python/bytecodes.c" + #line 2533 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3589 "Python/generated_cases.c.h" + #line 3588 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3597,7 +3596,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2543 "Python/bytecodes.c" + #line 2542 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3618,7 +3617,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3622 "Python/generated_cases.c.h" + #line 3621 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3627,7 +3626,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2582 "Python/bytecodes.c" + #line 2581 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3637,7 +3636,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3641 "Python/generated_cases.c.h" + #line 3640 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3651,7 +3650,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2594 "Python/bytecodes.c" + #line 2593 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3668,7 +3667,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3672 "Python/generated_cases.c.h" + #line 3671 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3682,7 +3681,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2613 "Python/bytecodes.c" + #line 2612 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3692,7 +3691,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3696 "Python/generated_cases.c.h" + #line 3695 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3706,7 +3705,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2625 "Python/bytecodes.c" + #line 2624 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3720,7 +3719,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3724 "Python/generated_cases.c.h" + #line 3723 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3729,16 +3728,16 @@ } TARGET(KW_NAMES) { - #line 2641 "Python/bytecodes.c" + #line 2640 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3737 "Python/generated_cases.c.h" + #line 3736 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2647 "Python/bytecodes.c" + #line 2646 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3751,7 +3750,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3755 "Python/generated_cases.c.h" + #line 3754 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3761,7 +3760,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2692 "Python/bytecodes.c" + #line 2691 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3843,7 +3842,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3847 "Python/generated_cases.c.h" + #line 3846 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3855,7 +3854,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2780 "Python/bytecodes.c" + #line 2779 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3865,7 +3864,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3869 "Python/generated_cases.c.h" + #line 3868 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3874,7 +3873,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2792 "Python/bytecodes.c" + #line 2791 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3900,7 +3899,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3904 "Python/generated_cases.c.h" + #line 3903 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3908,7 +3907,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2820 "Python/bytecodes.c" + #line 2819 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3944,7 +3943,7 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3948 "Python/generated_cases.c.h" + #line 3947 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3952,7 +3951,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2858 "Python/bytecodes.c" + #line 2857 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3962,7 +3961,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3966 "Python/generated_cases.c.h" + #line 3965 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3975,7 +3974,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2870 "Python/bytecodes.c" + #line 2869 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3986,7 +3985,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3990 "Python/generated_cases.c.h" + #line 3989 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4000,7 +3999,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2884 "Python/bytecodes.c" + #line 2883 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4011,7 +4010,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4015 "Python/generated_cases.c.h" + #line 4014 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4025,7 +4024,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2898 "Python/bytecodes.c" + #line 2897 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4047,7 +4046,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4051 "Python/generated_cases.c.h" + #line 4050 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4061,7 +4060,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2923 "Python/bytecodes.c" + #line 2922 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4089,7 +4088,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4093 "Python/generated_cases.c.h" + #line 4092 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4103,7 +4102,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2954 "Python/bytecodes.c" + #line 2953 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4135,7 +4134,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4139 "Python/generated_cases.c.h" + #line 4138 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4149,7 +4148,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2989 "Python/bytecodes.c" + #line 2988 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4181,7 +4180,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4185 "Python/generated_cases.c.h" + #line 4184 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4195,7 +4194,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3024 "Python/bytecodes.c" + #line 3023 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4220,7 +4219,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4224 "Python/generated_cases.c.h" + #line 4223 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4233,7 +4232,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3051 "Python/bytecodes.c" + #line 3050 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4260,7 +4259,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4264 "Python/generated_cases.c.h" + #line 4263 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4272,7 +4271,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3081 "Python/bytecodes.c" + #line 3080 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4290,14 +4289,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4294 "Python/generated_cases.c.h" + #line 4293 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3101 "Python/bytecodes.c" + #line 3100 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4328,7 +4327,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4332 "Python/generated_cases.c.h" + #line 4331 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4341,7 +4340,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3135 "Python/bytecodes.c" + #line 3134 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4370,7 +4369,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4374 "Python/generated_cases.c.h" + #line 4373 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4383,7 +4382,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3167 "Python/bytecodes.c" + #line 3166 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4412,7 +4411,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4416 "Python/generated_cases.c.h" + #line 4415 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4425,7 +4424,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3199 "Python/bytecodes.c" + #line 3198 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4453,7 +4452,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4457 "Python/generated_cases.c.h" + #line 4456 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4463,9 +4462,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3230 "Python/bytecodes.c" + #line 3229 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4469 "Python/generated_cases.c.h" + #line 4468 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4474,7 +4473,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3234 "Python/bytecodes.c" + #line 3233 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4536,14 +4535,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4540 "Python/generated_cases.c.h" + #line 4539 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3296 "Python/bytecodes.c" + #line 3295 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4547 "Python/generated_cases.c.h" + #line 4546 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4554,7 +4553,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3302 "Python/bytecodes.c" + #line 3301 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4566,7 +4565,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4570 "Python/generated_cases.c.h" + #line 4569 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4574,7 +4573,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3316 "Python/bytecodes.c" + #line 3315 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4599,14 +4598,14 @@ default: Py_UNREACHABLE(); } - #line 4603 "Python/generated_cases.c.h" + #line 4602 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3343 "Python/bytecodes.c" + #line 3342 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4627,7 +4626,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4631 "Python/generated_cases.c.h" + #line 4630 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4635,15 +4634,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3366 "Python/bytecodes.c" + #line 3365 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4641 "Python/generated_cases.c.h" + #line 4640 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3368 "Python/bytecodes.c" + #line 3367 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4647 "Python/generated_cases.c.h" + #line 4646 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4654,7 +4653,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3372 "Python/bytecodes.c" + #line 3371 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4689,7 +4688,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4693 "Python/generated_cases.c.h" + #line 4692 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4698,10 +4697,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3409 "Python/bytecodes.c" + #line 3408 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4705 "Python/generated_cases.c.h" + #line 4704 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4713,7 +4712,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3414 "Python/bytecodes.c" + #line 3413 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4728,12 +4727,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4732 "Python/generated_cases.c.h" + #line 4731 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3429 "Python/bytecodes.c" + #line 3428 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4737 "Python/generated_cases.c.h" + #line 4736 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4743,16 +4742,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3434 "Python/bytecodes.c" + #line 3433 "Python/bytecodes.c" assert(oparg >= 2); - #line 4749 "Python/generated_cases.c.h" + #line 4748 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3438 "Python/bytecodes.c" + #line 3437 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4764,26 +4763,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4768 "Python/generated_cases.c.h" + #line 4767 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3452 "Python/bytecodes.c" + #line 3451 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4774 "Python/generated_cases.c.h" + #line 4773 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3456 "Python/bytecodes.c" + #line 3455 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4781 "Python/generated_cases.c.h" + #line 4780 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3461 "Python/bytecodes.c" + #line 3460 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4792,12 +4791,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4796 "Python/generated_cases.c.h" + #line 4795 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3472 "Python/bytecodes.c" + #line 3471 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4806,12 +4805,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4810 "Python/generated_cases.c.h" + #line 4809 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3483 "Python/bytecodes.c" + #line 3482 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4823,12 +4822,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4827 "Python/generated_cases.c.h" + #line 4826 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3497 "Python/bytecodes.c" + #line 3496 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4840,30 +4839,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4844 "Python/generated_cases.c.h" + #line 4843 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3511 "Python/bytecodes.c" + #line 3510 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4855 "Python/generated_cases.c.h" + #line 4854 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3519 "Python/bytecodes.c" + #line 3518 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4862 "Python/generated_cases.c.h" + #line 4861 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3524 "Python/bytecodes.c" + #line 3523 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4869 "Python/generated_cases.c.h" + #line 4868 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index e144272fe2b82e..fcaccc022c8b2d 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -936,7 +936,7 @@ call_instrumentation_vector( } assert(!_PyErr_Occurred(tstate)); assert(args[0] == NULL); - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); @@ -1017,7 +1017,7 @@ _Py_call_instrumentation_jump( assert(frame->prev_instr == instr); /* Event should occur after the jump */ frame->prev_instr = target; - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); int to = (int)(target - _PyCode_CODE(code)); PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); if (to_obj == NULL) { @@ -1094,7 +1094,7 @@ int _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) { frame->prev_instr = instr; - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int i = (int)(instr - _PyCode_CODE(code)); @@ -1162,7 +1162,7 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, int _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) { - PyCodeObject *code = frame->f_code; + PyCodeObject *code = _PyFrame_GetCode(frame); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); int offset = (int)(instr - _PyCode_CODE(code)); @@ -1632,7 +1632,7 @@ instrument_all_executing_code_objects(PyInterpreterState *interp) { _PyInterpreterFrame *frame = ts->cframe->current_frame; while (frame) { if (frame->owner != FRAME_OWNED_BY_CSTACK) { - if (_Py_Instrument(frame->f_code, interp)) { + if (_Py_Instrument(_PyFrame_GetCode(frame), interp)) { return -1; } } diff --git a/Python/intrinsics.c b/Python/intrinsics.c index e34a856d2f3587..82f8cce7f92a71 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -148,14 +148,14 @@ stopiteration_error(PyThreadState* tstate, PyObject *exc) const char *msg = NULL; if (PyErr_GivenExceptionMatches(exc, PyExc_StopIteration)) { msg = "generator raised StopIteration"; - if (frame->f_code->co_flags & CO_ASYNC_GENERATOR) { + if (_PyFrame_GetCode(frame)->co_flags & CO_ASYNC_GENERATOR) { msg = "async generator raised StopIteration"; } - else if (frame->f_code->co_flags & CO_COROUTINE) { + else if (_PyFrame_GetCode(frame)->co_flags & CO_COROUTINE) { msg = "coroutine raised StopIteration"; } } - else if ((frame->f_code->co_flags & CO_ASYNC_GENERATOR) && + else if ((_PyFrame_GetCode(frame)->co_flags & CO_ASYNC_GENERATOR) && PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { /* code in `gen` raised a StopAsyncIteration error: diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 5143b79b0864d8..9cc48fc9493a05 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -244,7 +244,7 @@ sys_trace_line_func( "Missing frame when calling trace function."); return NULL; } - assert(args[0] == (PyObject *)frame->f_frame->f_code); + assert(args[0] == (PyObject *)_PyFrame_GetCode(frame->f_frame)); return trace_line(tstate, self, frame, line); } @@ -286,7 +286,6 @@ sys_trace_jump_func( "Missing frame when calling trace function."); return NULL; } - assert(code == frame->f_frame->f_code); if (!frame->f_trace_lines) { Py_RETURN_NONE; } diff --git a/Python/optimizer.c b/Python/optimizer.c index d721bfa2b2dea4..8f7a9727218655 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -148,15 +148,17 @@ PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer) _PyInterpreterFrame * _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer) { + PyCodeObject *code = (PyCodeObject *)frame->f_executable; + assert(PyCode_Check(code)); PyInterpreterState *interp = PyInterpreterState_Get(); - int index = get_executor_index(frame->f_code, src); + int index = get_executor_index(code, src); if (index < 0) { _PyFrame_SetStackPointer(frame, stack_pointer); return frame; } _PyOptimizerObject *opt = interp->optimizer; _PyExecutorObject *executor; - int err = opt->optimize(opt, frame->f_code, dest, &executor); + int err = opt->optimize(opt, code, dest, &executor); if (err <= 0) { if (err < 0) { return NULL; @@ -164,7 +166,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI _PyFrame_SetStackPointer(frame, stack_pointer); return frame; } - insert_executor(frame->f_code, src, index, executor); + insert_executor(code, src, index, executor); return executor->execute(executor, frame, stack_pointer); } diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 6a6f223d095d3b..b8885a303977d0 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -335,7 +335,7 @@ py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame, perf_status == PERF_STATUS_NO_INIT) { goto default_eval; } - PyCodeObject *co = frame->f_code; + PyCodeObject *co = _PyFrame_GetCode(frame); py_trampoline f = NULL; assert(extra_code_index != -1); int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d45b739c279737..ff9694886b6a45 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -737,22 +737,6 @@ pycore_init_types(PyInterpreterState *interp) return _PyStatus_OK(); } -static const uint8_t INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { - /* Put a NOP at the start, so that the IP points into - * the code, rather than before it */ - NOP, 0, - INTERPRETER_EXIT, 0, - /* RESUME at end makes sure that the frame appears incomplete */ - RESUME, 0 -}; - -static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = { - INTERPRETER_TRAMPOLINE_INSTRUCTIONS, - sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS), - 1, - "" -}; - static PyStatus pycore_init_builtins(PyThreadState *tstate) { @@ -786,10 +770,6 @@ pycore_init_builtins(PyThreadState *tstate) PyObject *object__getattribute__ = _PyType_Lookup(&PyBaseObject_Type, &_Py_ID(__getattribute__)); assert(object__getattribute__); interp->callable_cache.object__getattribute__ = object__getattribute__; - interp->interpreter_trampoline = _Py_MakeShimCode(&INTERPRETER_TRAMPOLINE_CODEDEF); - if (interp->interpreter_trampoline == NULL) { - return _PyStatus_ERR("failed to create interpreter trampoline."); - } if (_PyBuiltins_AddExceptions(bimod) < 0) { return _PyStatus_ERR("failed to add exceptions to builtins"); } diff --git a/Python/pystate.c b/Python/pystate.c index 52d6b29d78605a..2c39ac9eb8d171 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -892,7 +892,6 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) PyDict_Clear(interp->builtins); Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); - Py_CLEAR(interp->interpreter_trampoline); if (tstate->interp == interp) { /* We are now safe to fix tstate->_status.cleared. */ diff --git a/Python/traceback.c b/Python/traceback.c index a58df04b346010..c5787b5ea4678c 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -785,7 +785,7 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen } int code_offset = tb->tb_lasti; - PyCodeObject* code = frame->f_frame->f_code; + PyCodeObject* code = _PyFrame_GetCode(frame->f_frame); const Py_ssize_t source_line_len = PyUnicode_GET_LENGTH(source_line); int start_line; @@ -1164,7 +1164,7 @@ _Py_DumpASCII(int fd, PyObject *text) static void dump_frame(int fd, _PyInterpreterFrame *frame) { - PyCodeObject *code = frame->f_code; + PyCodeObject *code =_PyFrame_GetCode(frame); PUTS(fd, " File "); if (code->co_filename != NULL && PyUnicode_Check(code->co_filename)) diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index bc765623522288..f8ad939dccaccd 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -249,6 +249,7 @@ hashtable_compare_traceback(const void *key1, const void *key2) static void tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) { + assert(PyCode_Check(pyframe->f_executable)); frame->filename = &_Py_STR(anon_unknown); int lineno = PyUnstable_InterpreterFrame_GetLine(pyframe); if (lineno < 0) { @@ -256,7 +257,7 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) } frame->lineno = (unsigned int)lineno; - PyObject *filename = pyframe->f_code->co_filename; + PyObject *filename = filename = ((PyCodeObject *)pyframe->f_executable)->co_filename; if (filename == NULL) { #ifdef TRACE_DEBUG diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index c58dfe2d0b944e..9cce3f3b25c18d 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -327,6 +327,7 @@ Parser/parser.c - soft_keywords - Parser/tokenizer.c - type_comment_prefix - Python/ast_opt.c fold_unaryop ops - Python/ceval.c - binary_ops - +Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS - Python/codecs.c - Py_hexdigits - Python/codecs.c - ucnhash_capi - Python/codecs.c _PyCodecRegistry_Init methods - diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 6225d315281f02..78b0c08d25ab01 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1009,14 +1009,18 @@ def __init__(self, gdbval): self._gdbval = gdbval if not self.is_optimized_out(): - self.co = self._f_code() - self.co_name = self.co.pyop_field('co_name') - self.co_filename = self.co.pyop_field('co_filename') - - self.f_lasti = self._f_lasti() - self.co_nlocals = int_from_int(self.co.field('co_nlocals')) - pnames = self.co.field('co_localsplusnames') - self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames) + try: + self.co = self._f_code() + self.co_name = self.co.pyop_field('co_name') + self.co_filename = self.co.pyop_field('co_filename') + + self.f_lasti = self._f_lasti() + self.co_nlocals = int_from_int(self.co.field('co_nlocals')) + pnames = self.co.field('co_localsplusnames') + self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames) + self._is_code = True + except: + self._is_code = False def is_optimized_out(self): return self._gdbval.is_optimized_out @@ -1051,7 +1055,10 @@ def _f_builtins(self): return self._f_special("f_builtins") def _f_code(self): - return self._f_special("f_code", PyCodeObjectPtr.from_pyobject_ptr) + return self._f_special("f_executable", PyCodeObjectPtr.from_pyobject_ptr) + + def _f_executable(self): + return self._f_special("f_executable") def _f_nlocalsplus(self): return self._f_special("nlocalsplus", int_from_int) From 4a113e24a38e2537570e4d694f8e0c01354904c4 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 14 Jun 2023 15:19:27 +0100 Subject: [PATCH 041/446] Typing docs: move the deprecated stuff below the non-deprecated stuff (#105781) --- Doc/library/typing.rst | 1514 ++++++++++++++++++++-------------------- 1 file changed, 757 insertions(+), 757 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index aedef091e44c00..31861a0d613a88 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2388,1117 +2388,1117 @@ These are not used in annotations. They are building blocks for declaring types. .. versionchanged:: 3.13 Removed support for the keyword-argument method of creating ``TypedDict``\ s. -Generic concrete collections ----------------------------- - -Corresponding to built-in types -""""""""""""""""""""""""""""""" +Protocols +--------- -.. class:: Dict(dict, MutableMapping[KT, VT]) +These protocols are decorated with :func:`runtime_checkable`. - Deprecated alias to :class:`dict`. +.. class:: SupportsAbs - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Mapping` - rather than to use :class:`dict` or :class:`!typing.Dict`. + An ABC with one abstract method ``__abs__`` that is covariant + in its return type. - This type can be used as follows:: +.. class:: SupportsBytes - def count_words(text: str) -> Dict[str, int]: - ... + An ABC with one abstract method ``__bytes__``. - .. deprecated:: 3.9 - :class:`builtins.dict ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. class:: SupportsComplex -.. class:: List(list, MutableSequence[T]) + An ABC with one abstract method ``__complex__``. - Deprecated alias to :class:`list`. +.. class:: SupportsFloat - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`Sequence` or - :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. + An ABC with one abstract method ``__float__``. - This type may be used as follows:: +.. class:: SupportsIndex - def vec2[T: (int, float)](x: T, y: T) -> List[T]: - return [x, y] + An ABC with one abstract method ``__index__``. - def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: - return [item for item in vector if item > 0] + .. versionadded:: 3.8 - .. deprecated:: 3.9 - :class:`builtins.list ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. class:: SupportsInt -.. class:: Set(set, MutableSet[T]) + An ABC with one abstract method ``__int__``. - Deprecated alias to :class:`builtins.set `. +.. class:: SupportsRound - Note that to annotate arguments, it is preferred - to use an abstract collection type such as :class:`AbstractSet` - rather than to use :class:`set` or :class:`!typing.Set`. + An ABC with one abstract method ``__round__`` + that is covariant in its return type. - .. deprecated:: 3.9 - :class:`builtins.set ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +Functions and decorators +------------------------ -.. class:: FrozenSet(frozenset, AbstractSet[T_co]) +.. function:: cast(typ, val) - Deprecated alias to :class:`builtins.frozenset `. + Cast a value to a type. - .. deprecated:: 3.9 - :class:`builtins.frozenset ` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This returns the value unchanged. To the type checker this + signals that the return value has the designated type, but at + runtime we intentionally don't check anything (we want this + to be as fast as possible). -.. note:: :data:`Tuple` is a special form. +.. function:: assert_type(val, typ, /) -Corresponding to types in :mod:`collections` -"""""""""""""""""""""""""""""""""""""""""""" + Ask a static type checker to confirm that *val* has an inferred type of *typ*. -.. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) + At runtime this does nothing: it returns the first argument unchanged with no + checks or side effects, no matter the actual type of the argument. - Deprecated alias to :class:`collections.defaultdict`. + When a static type checker encounters a call to ``assert_type()``, it + emits an error if the value is not of the specified type:: - .. versionadded:: 3.5.2 + def greet(name: str) -> None: + assert_type(name, str) # OK, inferred type of `name` is `str` + assert_type(name, int) # type checker error - .. deprecated:: 3.9 - :class:`collections.defaultdict` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This function is useful for ensuring the type checker's understanding of a + script is in line with the developer's intentions:: -.. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) + def complex_function(arg: object): + # Do some complex type-narrowing logic, + # after which we hope the inferred type will be `int` + ... + # Test whether the type checker correctly understands our function + assert_type(arg, int) - Deprecated alias to :class:`collections.OrderedDict`. + .. versionadded:: 3.11 - .. versionadded:: 3.7.2 +.. function:: assert_never(arg, /) - .. deprecated:: 3.9 - :class:`collections.OrderedDict` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Ask a static type checker to confirm that a line of code is unreachable. -.. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) + Example:: - Deprecated alias to :class:`collections.ChainMap`. + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _ as unreachable: + assert_never(unreachable) - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 + Here, the annotations allow the type checker to infer that the + last case can never execute, because ``arg`` is either + an :class:`int` or a :class:`str`, and both options are covered by + earlier cases. - .. deprecated:: 3.9 - :class:`collections.ChainMap` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + If a type checker finds that a call to ``assert_never()`` is + reachable, it will emit an error. For example, if the type annotation + for ``arg`` was instead ``int | str | float``, the type checker would + emit an error pointing out that ``unreachable`` is of type :class:`float`. + For a call to ``assert_never`` to pass type checking, the inferred type of + the argument passed in must be the bottom type, :data:`Never`, and nothing + else. -.. class:: Counter(collections.Counter, Dict[T, int]) + At runtime, this throws an exception when called. - Deprecated alias to :class:`collections.Counter`. + .. seealso:: + `Unreachable Code and Exhaustiveness Checking + `__ has more + information about exhaustiveness checking with static typing. - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 + .. versionadded:: 3.11 - .. deprecated:: 3.9 - :class:`collections.Counter` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. function:: reveal_type(obj, /) -.. class:: Deque(deque, MutableSequence[T]) + Reveal the inferred static type of an expression. - Deprecated alias to :class:`collections.deque`. + When a static type checker encounters a call to this function, + it emits a diagnostic with the type of the argument. For example:: - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.1 + x: int = 1 + reveal_type(x) # Revealed type is "builtins.int" - .. deprecated:: 3.9 - :class:`collections.deque` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This can be useful when you want to debug how your type checker + handles a particular piece of code. -Other concrete types -"""""""""""""""""""" + The function returns its argument unchanged, which allows using + it within an expression:: -.. class:: IO - TextIO - BinaryIO + x = reveal_type(1) # Revealed type is "builtins.int" - Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` - and ``BinaryIO(IO[bytes])`` - represent the types of I/O streams such as returned by - :func:`open`. + Most type checkers support ``reveal_type()`` anywhere, even if the + name is not imported from ``typing``. Importing the name from + ``typing`` allows your code to run without runtime errors and + communicates intent more clearly. -.. class:: Pattern - Match + At runtime, this function prints the runtime type of its argument to stderr + and returns it unchanged:: - Deprecated aliases corresponding to the return types from - :func:`re.compile` and :func:`re.match`. + x = reveal_type(1) # prints "Runtime type is int" + print(x) # prints "1" - These types (and the corresponding functions) are generic over - :data:`AnyStr`. ``Pattern`` can be specialised as ``Pattern[str]`` or - ``Pattern[bytes]``; ``Match`` can be specialised as ``Match[str]`` or - ``Match[bytes]``. + .. versionadded:: 3.11 - .. deprecated:: 3.9 - Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. - See :pep:`585` and :ref:`types-genericalias`. +.. decorator:: dataclass_transform -.. class:: Text + Decorator to mark an object as providing + :func:`~dataclasses.dataclass`-like behavior. - Deprecated alias for :class:`str`. + ``dataclass_transform`` may be used to + decorate a class, metaclass, or a function that is itself a decorator. + The presence of ``@dataclass_transform()`` tells a static type checker that the + decorated object performs runtime "magic" that + transforms a class in a similar way to :func:`dataclasses.dataclass`. - ``Text`` is provided to supply a forward - compatible path for Python 2 code: in Python 2, ``Text`` is an alias for - ``unicode``. + Example usage with a decorator function: - Use ``Text`` to indicate that a value must contain a unicode string in - a manner that is compatible with both Python 2 and Python 3:: + .. testcode:: - def add_unicode_checkmark(text: Text) -> Text: - return text + u' \u2713' + @dataclass_transform() + def create_model[T](cls: type[T]) -> type[T]: + ... + return cls - .. versionadded:: 3.5.2 + @create_model + class CustomerModel: + id: int + name: str - .. deprecated:: 3.11 - Python 2 is no longer supported, and most type checkers also no longer - support type checking Python 2 code. Removal of the alias is not - currently planned, but users are encouraged to use - :class:`str` instead of ``Text``. + On a base class:: -Abstract Base Classes ---------------------- + @dataclass_transform() + class ModelBase: ... -Corresponding to collections in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" + class CustomerModel(ModelBase): + id: int + name: str -.. class:: AbstractSet(Collection[T_co]) + On a metaclass:: - Deprecated alias to :class:`collections.abc.Set`. + @dataclass_transform() + class ModelMeta(type): ... - .. deprecated:: 3.9 - :class:`collections.abc.Set` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + class ModelBase(metaclass=ModelMeta): ... -.. class:: ByteString(Sequence[int]) + class CustomerModel(ModelBase): + id: int + name: str - This type represents the types :class:`bytes`, :class:`bytearray`, - and :class:`memoryview` of byte sequences. + The ``CustomerModel`` classes defined above will + be treated by type checkers similarly to classes created with + :func:`@dataclasses.dataclass `. + For example, type checkers will assume these classes have + ``__init__`` methods that accept ``id`` and ``name``. - .. deprecated-removed:: 3.9 3.14 - Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. - -.. class:: Collection(Sized, Iterable[T_co], Container[T_co]) + The decorated class, metaclass, or function may accept the following bool + arguments which type checkers will assume have the same effect as they + would have on the + :func:`@dataclasses.dataclass` decorator: ``init``, + ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, + ``kw_only``, and ``slots``. It must be possible for the value of these + arguments (``True`` or ``False``) to be statically evaluated. - Deprecated alias to :class:`collections.abc.Collection`. + The arguments to the ``dataclass_transform`` decorator can be used to + customize the default behaviors of the decorated class, metaclass, or + function: - .. versionadded:: 3.6.0 + * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + ``True`` or ``False`` if it is omitted by the caller. + * ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + * ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + * ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. - .. deprecated:: 3.9 - :class:`collections.abc.Collection` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. versionadded:: 3.12 + * ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + * Arbitrary other keyword arguments are accepted in order to allow for + possible future extensions. -.. class:: Container(Generic[T_co]) + Type checkers recognize the following optional arguments on field + specifiers: - Deprecated alias to :class:`collections.abc.Container`. + * ``init`` indicates whether the field should be included in the + synthesized ``__init__`` method. If unspecified, ``init`` defaults to + ``True``. + * ``default`` provides the default value for the field. + * ``default_factory`` provides a runtime callback that returns the + default value for the field. If neither ``default`` nor + ``default_factory`` are specified, the field is assumed to have no + default value and must be provided a value when the class is + instantiated. + * ``factory`` is an alias for ``default_factory``. + * ``kw_only`` indicates whether the field should be marked as + keyword-only. If ``True``, the field will be keyword-only. If + ``False``, it will not be keyword-only. If unspecified, the value of + the ``kw_only`` parameter on the object decorated with + ``dataclass_transform`` will be used, or if that is unspecified, the + value of ``kw_only_default`` on ``dataclass_transform`` will be used. + * ``alias`` provides an alternative name for the field. This alternative + name is used in the synthesized ``__init__`` method. - .. deprecated:: 3.9 - :class:`collections.abc.Container` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + It has no other runtime effect. -.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) + See :pep:`681` for more details. - Deprecated alias to :class:`collections.abc.ItemsView`. + .. versionadded:: 3.11 - .. deprecated:: 3.9 - :class:`collections.abc.ItemsView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. +.. decorator:: overload -.. class:: KeysView(MappingView, AbstractSet[KT_co]) + Decorator for creating overloaded functions and methods. - Deprecated alias to :class:`collections.abc.KeysView`. + The ``@overload`` decorator allows describing functions and methods + that support multiple different combinations of argument types. A series + of ``@overload``-decorated definitions must be followed by exactly one + non-``@overload``-decorated definition (for the same function/method). - .. deprecated:: 3.9 - :class:`collections.abc.KeysView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + ``@overload``-decorated definitions are for the benefit of the + type checker only, since they will be overwritten by the + non-``@overload``-decorated definition. The non-``@overload``-decorated + definition, meanwhile, will be used at + runtime but should be ignored by a type checker. At runtime, calling + an ``@overload``-decorated function directly will raise + :exc:`NotImplementedError`. -.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) + An example of overload that gives a more + precise type than can be expressed using a union or a type variable: - Deprecated alias to :class:`collections.abc.Mapping`. + .. testcode:: - This type can be used as follows:: + @overload + def process(response: None) -> None: + ... + @overload + def process(response: int) -> tuple[int, str]: + ... + @overload + def process(response: bytes) -> str: + ... + def process(response): + ... # actual implementation goes here - def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: - return word_list[word] + See :pep:`484` for more details and comparison with other typing semantics. - .. deprecated:: 3.9 - :class:`collections.abc.Mapping` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. versionchanged:: 3.11 + Overloaded functions can now be introspected at runtime using + :func:`get_overloads`. -.. class:: MappingView(Sized) - Deprecated alias to :class:`collections.abc.MappingView`. +.. function:: get_overloads(func) - .. deprecated:: 3.9 - :class:`collections.abc.MappingView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Return a sequence of :func:`@overload `-decorated definitions for + *func*. -.. class:: MutableMapping(Mapping[KT, VT]) + *func* is the function object for the implementation of the + overloaded function. For example, given the definition of ``process`` in + the documentation for :func:`@overload `, + ``get_overloads(process)`` will return a sequence of three function objects + for the three defined overloads. If called on a function with no overloads, + ``get_overloads()`` returns an empty sequence. - Deprecated alias to :class:`collections.abc.MutableMapping`. + ``get_overloads()`` can be used for introspecting an overloaded function at + runtime. - .. deprecated:: 3.9 - :class:`collections.abc.MutableMapping` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. versionadded:: 3.11 -.. class:: MutableSequence(Sequence[T]) - Deprecated alias to :class:`collections.abc.MutableSequence`. +.. function:: clear_overloads() - .. deprecated:: 3.9 - :class:`collections.abc.MutableSequence` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Clear all registered overloads in the internal registry. -.. class:: MutableSet(AbstractSet[T]) + This can be used to reclaim the memory used by the registry. - Deprecated alias to :class:`collections.abc.MutableSet`. + .. versionadded:: 3.11 - .. deprecated:: 3.9 - :class:`collections.abc.MutableSet` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. -.. class:: Sequence(Reversible[T_co], Collection[T_co]) +.. decorator:: final - Deprecated alias to :class:`collections.abc.Sequence`. + Decorator to indicate final methods and final classes. - .. deprecated:: 3.9 - :class:`collections.abc.Sequence` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Decorating a method with ``@final`` indicates to a type checker that the + method cannot be overridden in a subclass. Decorating a class with ``@final`` + indicates that it cannot be subclassed. -.. class:: ValuesView(MappingView, Collection[_VT_co]) + For example:: - Deprecated alias to :class:`collections.abc.ValuesView`. + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... - .. deprecated:: 3.9 - :class:`collections.abc.ValuesView` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... -Corresponding to other types in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" + There is no runtime checking of these properties. See :pep:`591` for + more details. -.. class:: Iterable(Generic[T_co]) + .. versionadded:: 3.8 - Deprecated alias to :class:`collections.abc.Iterable`. + .. versionchanged:: 3.11 + The decorator will now attempt to set a ``__final__`` attribute to ``True`` + on the decorated object. Thus, a check like + ``if getattr(obj, "__final__", False)`` can be used at runtime + to determine whether an object ``obj`` has been marked as final. + If the decorated object does not support setting attributes, + the decorator returns the object unchanged without raising an exception. - .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. -.. class:: Iterator(Iterable[T_co]) +.. decorator:: no_type_check - Deprecated alias to :class:`collections.abc.Iterator`. + Decorator to indicate that annotations are not type hints. - .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + This works as a class or function :term:`decorator`. With a class, it + applies recursively to all methods and classes defined in that class + (but not to methods defined in its superclasses or subclasses). Type + checkers will ignore all annotations in a function or class with this + decorator. -.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) + ``@no_type_check`` mutates the decorated object in place. - Deprecated alias to :class:`collections.abc.Generator`. +.. decorator:: no_type_check_decorator - A generator can be annotated by the generic type - ``Generator[YieldType, SendType, ReturnType]``. For example:: + Decorator to give another decorator the :func:`no_type_check` effect. - def echo_round() -> Generator[int, float, str]: - sent = yield 0 - while sent >= 0: - sent = yield round(sent) - return 'Done' + This wraps the decorator with something that wraps the decorated + function in :func:`no_type_check`. - Note that unlike many other generics in the typing module, the ``SendType`` - of :class:`Generator` behaves contravariantly, not covariantly or - invariantly. - If your generator will only yield values, set the ``SendType`` and - ``ReturnType`` to ``None``:: +.. decorator:: override - def infinite_stream(start: int) -> Generator[int, None, None]: - while True: - yield start - start += 1 + Decorator to indicate that a method in a subclass is intended to override a + method or attribute in a superclass. - Alternatively, annotate your generator as having a return type of - either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: + Type checkers should emit an error if a method decorated with ``@override`` + does not, in fact, override anything. + This helps prevent bugs that may occur when a base class is changed without + an equivalent change to a child class. - def infinite_stream(start: int) -> Iterator[int]: - while True: - yield start - start += 1 + For example: - .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. testcode:: -.. class:: Hashable + class Base: + def log_status(self) -> None: + ... - Deprecated alias to :class:`collections.abc.Hashable`. + class Sub(Base): + @override + def log_status(self) -> None: # Okay: overrides Base.log_status + ... - .. deprecated:: 3.12 - Use :class:`collections.abc.Hashable` directly instead. - -.. class:: Reversible(Iterable[T_co]) - - Deprecated alias to :class:`collections.abc.Reversible`. - - .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + @override + def done(self) -> None: # Error reported by type checker + ... -.. class:: Sized + There is no runtime checking of this property. - Deprecated alias to :class:`collections.abc.Sized`. + The decorator will attempt to set an ``__override__`` attribute to ``True`` on + the decorated object. Thus, a check like + ``if getattr(obj, "__override__", False)`` can be used at runtime to determine + whether an object ``obj`` has been marked as an override. If the decorated object + does not support setting attributes, the decorator returns the object unchanged + without raising an exception. - .. deprecated:: 3.12 - Use :class:`collections.abc.Sized` directly instead. + See :pep:`698` for more details. -Asynchronous programming -"""""""""""""""""""""""" + .. versionadded:: 3.12 -.. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) - Deprecated alias to :class:`collections.abc.Coroutine`. +.. decorator:: type_check_only - The variance and order of type variables - correspond to those of :class:`Generator`, for example:: + Decorator to mark a class or function as unavailable at runtime. - from collections.abc import Coroutine - c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere - x = c.send('hi') # Inferred type of 'x' is list[str] - async def bar() -> None: - y = await c # Inferred type of 'y' is int + This decorator is itself not available at runtime. It is mainly + intended to mark classes that are defined in type stub files if + an implementation returns an instance of a private class:: - .. versionadded:: 3.5.3 + @type_check_only + class Response: # private or not available at runtime + code: int + def get_header(self, name: str) -> str: ... - .. deprecated:: 3.9 - :class:`collections.abc.Coroutine` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + def fetch_response() -> Response: ... -.. class:: AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType]) + Note that returning instances of private classes is not recommended. + It is usually preferable to make such classes public. - Deprecated alias to :class:`collections.abc.AsyncGenerator`. +Introspection helpers +--------------------- - An async generator can be annotated by the generic type - ``AsyncGenerator[YieldType, SendType]``. For example:: +.. function:: get_type_hints(obj, globalns=None, localns=None, include_extras=False) - async def echo_round() -> AsyncGenerator[int, float]: - sent = yield 0 - while sent >= 0.0: - rounded = await round(sent) - sent = yield rounded + Return a dictionary containing type hints for a function, method, module + or class object. - Unlike normal generators, async generators cannot return a value, so there - is no ``ReturnType`` type parameter. As with :class:`Generator`, the - ``SendType`` behaves contravariantly. + This is often the same as ``obj.__annotations__``. In addition, + forward references encoded as string literals are handled by evaluating + them in ``globals`` and ``locals`` namespaces. For a class ``C``, return + a dictionary constructed by merging all the ``__annotations__`` along + ``C.__mro__`` in reverse order. - If your generator will only yield values, set the ``SendType`` to - ``None``:: + The function recursively replaces all ``Annotated[T, ...]`` with ``T``, + unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for + more information). For example: - async def infinite_stream(start: int) -> AsyncGenerator[int, None]: - while True: - yield start - start = await increment(start) + .. testcode:: - Alternatively, annotate your generator as having a return type of - either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``:: + class Student(NamedTuple): + name: Annotated[str, 'some marker'] - async def infinite_stream(start: int) -> AsyncIterator[int]: - while True: - yield start - start = await increment(start) + assert get_type_hints(Student) == {'name': str} + assert get_type_hints(Student, include_extras=False) == {'name': str} + assert get_type_hints(Student, include_extras=True) == { + 'name': Annotated[str, 'some marker'] + } - .. versionadded:: 3.6.1 + .. note:: - .. deprecated:: 3.9 - :class:`collections.abc.AsyncGenerator` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + :func:`get_type_hints` does not work with imported + :ref:`type aliases ` that include forward references. + Enabling postponed evaluation of annotations (:pep:`563`) may remove + the need for most forward references. -.. class:: AsyncIterable(Generic[T_co]) + .. versionchanged:: 3.9 + Added ``include_extras`` parameter as part of :pep:`593`. + See the documentation on :data:`Annotated` for more information. - Deprecated alias to :class:`collections.abc.AsyncIterable`. + .. versionchanged:: 3.11 + Previously, ``Optional[t]`` was added for function and method annotations + if a default value equal to ``None`` was set. + Now the annotation is returned unchanged. - .. versionadded:: 3.5.2 +.. function:: get_origin(tp) - .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Get the unsubscripted version of a type: for a typing object of the form + ``X[Y, Z, ...]`` return ``X``. -.. class:: AsyncIterator(AsyncIterable[T_co]) + If ``X`` is a typing-module alias for a builtin or + :mod:`collections` class, it will be normalized to the original class. + If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, + return the underlying :class:`ParamSpec`. + Return ``None`` for unsupported objects. - Deprecated alias to :class:`collections.abc.AsyncIterator`. + Examples: - .. versionadded:: 3.5.2 + .. testcode:: - .. deprecated:: 3.9 - :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + assert get_origin(str) is None + assert get_origin(Dict[str, int]) is dict + assert get_origin(Union[int, str]) is Union + P = ParamSpec('P') + assert get_origin(P.args) is P + assert get_origin(P.kwargs) is P -.. class:: Awaitable(Generic[T_co]) + .. versionadded:: 3.8 - Deprecated alias to :class:`collections.abc.Awaitable`. +.. function:: get_args(tp) - .. versionadded:: 3.5.2 + Get type arguments with all substitutions performed: for a typing object + of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. - .. deprecated:: 3.9 - :class:`collections.abc.Awaitable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + If ``X`` is a union or :class:`Literal` contained in another + generic type, the order of ``(Y, Z, ...)`` may be different from the order + of the original arguments ``[Y, Z, ...]`` due to type caching. + Return ``()`` for unsupported objects. + Examples: -Context manager types -""""""""""""""""""""" + .. testcode:: -.. class:: ContextManager(Generic[T_co]) + assert get_args(int) == () + assert get_args(Dict[int, str]) == (int, str) + assert get_args(Union[int, str]) == (int, str) - Deprecated alias to :class:`contextlib.AbstractContextManager`. + .. versionadded:: 3.8 - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.0 +.. function:: get_protocol_members(tp) - .. deprecated:: 3.9 - :class:`contextlib.AbstractContextManager` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + Return the set of members defined in a :class:`Protocol`. -.. class:: AsyncContextManager(Generic[T_co]) + :: - Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`. + >>> from typing import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) - .. versionadded:: 3.5.4 - .. versionadded:: 3.6.2 + Raise :exc:`TypeError` for arguments that are not Protocols. - .. deprecated:: 3.9 - :class:`contextlib.AbstractAsyncContextManager` - now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. + .. versionadded:: 3.13 -Protocols ---------- +.. function:: is_protocol(tp) -These protocols are decorated with :func:`runtime_checkable`. + Determine if a type is a :class:`Protocol`. -.. class:: SupportsAbs + For example:: - An ABC with one abstract method ``__abs__`` that is covariant - in its return type. + class P(Protocol): + def a(self) -> str: ... + b: int -.. class:: SupportsBytes + is_protocol(P) # => True + is_protocol(int) # => False - An ABC with one abstract method ``__bytes__``. + .. versionadded:: 3.13 -.. class:: SupportsComplex +.. function:: is_typeddict(tp) - An ABC with one abstract method ``__complex__``. + Check if a type is a :class:`TypedDict`. -.. class:: SupportsFloat + For example: - An ABC with one abstract method ``__float__``. + .. testcode:: -.. class:: SupportsIndex + class Film(TypedDict): + title: str + year: int - An ABC with one abstract method ``__index__``. + assert is_typeddict(Film) + assert not is_typeddict(list | str) - .. versionadded:: 3.8 + # TypedDict is a factory for creating typed dicts, + # not a typed dict itself + assert not is_typeddict(TypedDict) -.. class:: SupportsInt + .. versionadded:: 3.10 - An ABC with one abstract method ``__int__``. +.. class:: ForwardRef -.. class:: SupportsRound + Class used for internal typing representation of string forward references. - An ABC with one abstract method ``__round__`` - that is covariant in its return type. + For example, ``List["SomeClass"]`` is implicitly transformed into + ``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by + a user, but may be used by introspection tools. -Functions and decorators ------------------------- + .. note:: + :pep:`585` generic types such as ``list["SomeClass"]`` will not be + implicitly transformed into ``list[ForwardRef("SomeClass")]`` and thus + will not automatically resolve to ``list[SomeClass]``. -.. function:: cast(typ, val) + .. versionadded:: 3.7.4 - Cast a value to a type. +Constant +-------- - This returns the value unchanged. To the type checker this - signals that the return value has the designated type, but at - runtime we intentionally don't check anything (we want this - to be as fast as possible). +.. data:: TYPE_CHECKING -.. function:: assert_type(val, typ, /) + A special constant that is assumed to be ``True`` by 3rd party static + type checkers. It is ``False`` at runtime. - Ask a static type checker to confirm that *val* has an inferred type of *typ*. + Usage:: - At runtime this does nothing: it returns the first argument unchanged with no - checks or side effects, no matter the actual type of the argument. + if TYPE_CHECKING: + import expensive_mod - When a static type checker encounters a call to ``assert_type()``, it - emits an error if the value is not of the specified type:: + def fun(arg: 'expensive_mod.SomeType') -> None: + local_var: expensive_mod.AnotherType = other_fun() - def greet(name: str) -> None: - assert_type(name, str) # OK, inferred type of `name` is `str` - assert_type(name, int) # type checker error + The first type annotation must be enclosed in quotes, making it a + "forward reference", to hide the ``expensive_mod`` reference from the + interpreter runtime. Type annotations for local variables are not + evaluated, so the second annotation does not need to be enclosed in quotes. - This function is useful for ensuring the type checker's understanding of a - script is in line with the developer's intentions:: + .. note:: - def complex_function(arg: object): - # Do some complex type-narrowing logic, - # after which we hope the inferred type will be `int` - ... - # Test whether the type checker correctly understands our function - assert_type(arg, int) + If ``from __future__ import annotations`` is used, + annotations are not evaluated at function definition time. + Instead, they are stored as strings in ``__annotations__``. + This makes it unnecessary to use quotes around the annotation + (see :pep:`563`). - .. versionadded:: 3.11 + .. versionadded:: 3.5.2 -.. function:: assert_never(arg, /) +Generic concrete collections +---------------------------- - Ask a static type checker to confirm that a line of code is unreachable. +Corresponding to built-in types +""""""""""""""""""""""""""""""" - Example:: +.. class:: Dict(dict, MutableMapping[KT, VT]) - def int_or_str(arg: int | str) -> None: - match arg: - case int(): - print("It's an int") - case str(): - print("It's a str") - case _ as unreachable: - assert_never(unreachable) + Deprecated alias to :class:`dict`. - Here, the annotations allow the type checker to infer that the - last case can never execute, because ``arg`` is either - an :class:`int` or a :class:`str`, and both options are covered by - earlier cases. + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`Mapping` + rather than to use :class:`dict` or :class:`!typing.Dict`. - If a type checker finds that a call to ``assert_never()`` is - reachable, it will emit an error. For example, if the type annotation - for ``arg`` was instead ``int | str | float``, the type checker would - emit an error pointing out that ``unreachable`` is of type :class:`float`. - For a call to ``assert_never`` to pass type checking, the inferred type of - the argument passed in must be the bottom type, :data:`Never`, and nothing - else. + This type can be used as follows:: - At runtime, this throws an exception when called. + def count_words(text: str) -> Dict[str, int]: + ... - .. seealso:: - `Unreachable Code and Exhaustiveness Checking - `__ has more - information about exhaustiveness checking with static typing. + .. deprecated:: 3.9 + :class:`builtins.dict ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionadded:: 3.11 +.. class:: List(list, MutableSequence[T]) -.. function:: reveal_type(obj, /) + Deprecated alias to :class:`list`. - Reveal the inferred static type of an expression. + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`Sequence` or + :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`. - When a static type checker encounters a call to this function, - it emits a diagnostic with the type of the argument. For example:: + This type may be used as follows:: - x: int = 1 - reveal_type(x) # Revealed type is "builtins.int" + def vec2[T: (int, float)](x: T, y: T) -> List[T]: + return [x, y] - This can be useful when you want to debug how your type checker - handles a particular piece of code. + def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: + return [item for item in vector if item > 0] - The function returns its argument unchanged, which allows using - it within an expression:: + .. deprecated:: 3.9 + :class:`builtins.list ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - x = reveal_type(1) # Revealed type is "builtins.int" +.. class:: Set(set, MutableSet[T]) - Most type checkers support ``reveal_type()`` anywhere, even if the - name is not imported from ``typing``. Importing the name from - ``typing`` allows your code to run without runtime errors and - communicates intent more clearly. + Deprecated alias to :class:`builtins.set `. - At runtime, this function prints the runtime type of its argument to stderr - and returns it unchanged:: + Note that to annotate arguments, it is preferred + to use an abstract collection type such as :class:`AbstractSet` + rather than to use :class:`set` or :class:`!typing.Set`. - x = reveal_type(1) # prints "Runtime type is int" - print(x) # prints "1" + .. deprecated:: 3.9 + :class:`builtins.set ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionadded:: 3.11 +.. class:: FrozenSet(frozenset, AbstractSet[T_co]) -.. decorator:: dataclass_transform + Deprecated alias to :class:`builtins.frozenset `. - Decorator to mark an object as providing - :func:`~dataclasses.dataclass`-like behavior. + .. deprecated:: 3.9 + :class:`builtins.frozenset ` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - ``dataclass_transform`` may be used to - decorate a class, metaclass, or a function that is itself a decorator. - The presence of ``@dataclass_transform()`` tells a static type checker that the - decorated object performs runtime "magic" that - transforms a class in a similar way to :func:`dataclasses.dataclass`. +.. note:: :data:`Tuple` is a special form. - Example usage with a decorator function: +Corresponding to types in :mod:`collections` +"""""""""""""""""""""""""""""""""""""""""""" - .. testcode:: +.. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) - @dataclass_transform() - def create_model[T](cls: type[T]) -> type[T]: - ... - return cls + Deprecated alias to :class:`collections.defaultdict`. - @create_model - class CustomerModel: - id: int - name: str + .. versionadded:: 3.5.2 - On a base class:: + .. deprecated:: 3.9 + :class:`collections.defaultdict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - @dataclass_transform() - class ModelBase: ... +.. class:: OrderedDict(collections.OrderedDict, MutableMapping[KT, VT]) - class CustomerModel(ModelBase): - id: int - name: str + Deprecated alias to :class:`collections.OrderedDict`. - On a metaclass:: + .. versionadded:: 3.7.2 - @dataclass_transform() - class ModelMeta(type): ... + .. deprecated:: 3.9 + :class:`collections.OrderedDict` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - class ModelBase(metaclass=ModelMeta): ... +.. class:: ChainMap(collections.ChainMap, MutableMapping[KT, VT]) - class CustomerModel(ModelBase): - id: int - name: str + Deprecated alias to :class:`collections.ChainMap`. - The ``CustomerModel`` classes defined above will - be treated by type checkers similarly to classes created with - :func:`@dataclasses.dataclass `. - For example, type checkers will assume these classes have - ``__init__`` methods that accept ``id`` and ``name``. + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 - The decorated class, metaclass, or function may accept the following bool - arguments which type checkers will assume have the same effect as they - would have on the - :func:`@dataclasses.dataclass` decorator: ``init``, - ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, - ``kw_only``, and ``slots``. It must be possible for the value of these - arguments (``True`` or ``False``) to be statically evaluated. + .. deprecated:: 3.9 + :class:`collections.ChainMap` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - The arguments to the ``dataclass_transform`` decorator can be used to - customize the default behaviors of the decorated class, metaclass, or - function: +.. class:: Counter(collections.Counter, Dict[T, int]) - * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - ``True`` or ``False`` if it is omitted by the caller. - * ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. + Deprecated alias to :class:`collections.Counter`. - .. versionadded:: 3.12 - * ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - * Arbitrary other keyword arguments are accepted in order to allow for - possible future extensions. + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 - Type checkers recognize the following optional arguments on field - specifiers: + .. deprecated:: 3.9 + :class:`collections.Counter` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - * ``init`` indicates whether the field should be included in the - synthesized ``__init__`` method. If unspecified, ``init`` defaults to - ``True``. - * ``default`` provides the default value for the field. - * ``default_factory`` provides a runtime callback that returns the - default value for the field. If neither ``default`` nor - ``default_factory`` are specified, the field is assumed to have no - default value and must be provided a value when the class is - instantiated. - * ``factory`` is an alias for ``default_factory``. - * ``kw_only`` indicates whether the field should be marked as - keyword-only. If ``True``, the field will be keyword-only. If - ``False``, it will not be keyword-only. If unspecified, the value of - the ``kw_only`` parameter on the object decorated with - ``dataclass_transform`` will be used, or if that is unspecified, the - value of ``kw_only_default`` on ``dataclass_transform`` will be used. - * ``alias`` provides an alternative name for the field. This alternative - name is used in the synthesized ``__init__`` method. +.. class:: Deque(deque, MutableSequence[T]) - At runtime, this decorator records its arguments in the - ``__dataclass_transform__`` attribute on the decorated object. - It has no other runtime effect. + Deprecated alias to :class:`collections.deque`. - See :pep:`681` for more details. + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.1 - .. versionadded:: 3.11 + .. deprecated:: 3.9 + :class:`collections.deque` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. decorator:: overload +Other concrete types +"""""""""""""""""""" - Decorator for creating overloaded functions and methods. +.. class:: IO + TextIO + BinaryIO - The ``@overload`` decorator allows describing functions and methods - that support multiple different combinations of argument types. A series - of ``@overload``-decorated definitions must be followed by exactly one - non-``@overload``-decorated definition (for the same function/method). + Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` + and ``BinaryIO(IO[bytes])`` + represent the types of I/O streams such as returned by + :func:`open`. - ``@overload``-decorated definitions are for the benefit of the - type checker only, since they will be overwritten by the - non-``@overload``-decorated definition. The non-``@overload``-decorated - definition, meanwhile, will be used at - runtime but should be ignored by a type checker. At runtime, calling - an ``@overload``-decorated function directly will raise - :exc:`NotImplementedError`. +.. class:: Pattern + Match - An example of overload that gives a more - precise type than can be expressed using a union or a type variable: + Deprecated aliases corresponding to the return types from + :func:`re.compile` and :func:`re.match`. - .. testcode:: + These types (and the corresponding functions) are generic over + :data:`AnyStr`. ``Pattern`` can be specialised as ``Pattern[str]`` or + ``Pattern[bytes]``; ``Match`` can be specialised as ``Match[str]`` or + ``Match[bytes]``. - @overload - def process(response: None) -> None: - ... - @overload - def process(response: int) -> tuple[int, str]: - ... - @overload - def process(response: bytes) -> str: - ... - def process(response): - ... # actual implementation goes here + .. deprecated:: 3.9 + Classes ``Pattern`` and ``Match`` from :mod:`re` now support ``[]``. + See :pep:`585` and :ref:`types-genericalias`. - See :pep:`484` for more details and comparison with other typing semantics. +.. class:: Text - .. versionchanged:: 3.11 - Overloaded functions can now be introspected at runtime using - :func:`get_overloads`. + Deprecated alias for :class:`str`. + ``Text`` is provided to supply a forward + compatible path for Python 2 code: in Python 2, ``Text`` is an alias for + ``unicode``. -.. function:: get_overloads(func) + Use ``Text`` to indicate that a value must contain a unicode string in + a manner that is compatible with both Python 2 and Python 3:: - Return a sequence of :func:`@overload `-decorated definitions for - *func*. + def add_unicode_checkmark(text: Text) -> Text: + return text + u' \u2713' - *func* is the function object for the implementation of the - overloaded function. For example, given the definition of ``process`` in - the documentation for :func:`@overload `, - ``get_overloads(process)`` will return a sequence of three function objects - for the three defined overloads. If called on a function with no overloads, - ``get_overloads()`` returns an empty sequence. + .. versionadded:: 3.5.2 - ``get_overloads()`` can be used for introspecting an overloaded function at - runtime. + .. deprecated:: 3.11 + Python 2 is no longer supported, and most type checkers also no longer + support type checking Python 2 code. Removal of the alias is not + currently planned, but users are encouraged to use + :class:`str` instead of ``Text``. - .. versionadded:: 3.11 +Abstract Base Classes +--------------------- +Corresponding to collections in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" -.. function:: clear_overloads() +.. class:: AbstractSet(Collection[T_co]) - Clear all registered overloads in the internal registry. + Deprecated alias to :class:`collections.abc.Set`. - This can be used to reclaim the memory used by the registry. + .. deprecated:: 3.9 + :class:`collections.abc.Set` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionadded:: 3.11 +.. class:: ByteString(Sequence[int]) + This type represents the types :class:`bytes`, :class:`bytearray`, + and :class:`memoryview` of byte sequences. -.. decorator:: final + .. deprecated-removed:: 3.9 3.14 + Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``. - Decorator to indicate final methods and final classes. +.. class:: Collection(Sized, Iterable[T_co], Container[T_co]) - Decorating a method with ``@final`` indicates to a type checker that the - method cannot be overridden in a subclass. Decorating a class with ``@final`` - indicates that it cannot be subclassed. + Deprecated alias to :class:`collections.abc.Collection`. - For example:: + .. versionadded:: 3.6.0 - class Base: - @final - def done(self) -> None: - ... - class Sub(Base): - def done(self) -> None: # Error reported by type checker - ... + .. deprecated:: 3.9 + :class:`collections.abc.Collection` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - @final - class Leaf: - ... - class Other(Leaf): # Error reported by type checker - ... +.. class:: Container(Generic[T_co]) - There is no runtime checking of these properties. See :pep:`591` for - more details. + Deprecated alias to :class:`collections.abc.Container`. - .. versionadded:: 3.8 + .. deprecated:: 3.9 + :class:`collections.abc.Container` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionchanged:: 3.11 - The decorator will now attempt to set a ``__final__`` attribute to ``True`` - on the decorated object. Thus, a check like - ``if getattr(obj, "__final__", False)`` can be used at runtime - to determine whether an object ``obj`` has been marked as final. - If the decorated object does not support setting attributes, - the decorator returns the object unchanged without raising an exception. +.. class:: ItemsView(MappingView, AbstractSet[tuple[KT_co, VT_co]]) + Deprecated alias to :class:`collections.abc.ItemsView`. -.. decorator:: no_type_check + .. deprecated:: 3.9 + :class:`collections.abc.ItemsView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Decorator to indicate that annotations are not type hints. +.. class:: KeysView(MappingView, AbstractSet[KT_co]) - This works as a class or function :term:`decorator`. With a class, it - applies recursively to all methods and classes defined in that class - (but not to methods defined in its superclasses or subclasses). Type - checkers will ignore all annotations in a function or class with this - decorator. + Deprecated alias to :class:`collections.abc.KeysView`. - ``@no_type_check`` mutates the decorated object in place. + .. deprecated:: 3.9 + :class:`collections.abc.KeysView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. decorator:: no_type_check_decorator +.. class:: Mapping(Collection[KT], Generic[KT, VT_co]) - Decorator to give another decorator the :func:`no_type_check` effect. + Deprecated alias to :class:`collections.abc.Mapping`. - This wraps the decorator with something that wraps the decorated - function in :func:`no_type_check`. + This type can be used as follows:: + def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: + return word_list[word] -.. decorator:: override + .. deprecated:: 3.9 + :class:`collections.abc.Mapping` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Decorator to indicate that a method in a subclass is intended to override a - method or attribute in a superclass. +.. class:: MappingView(Sized) - Type checkers should emit an error if a method decorated with ``@override`` - does not, in fact, override anything. - This helps prevent bugs that may occur when a base class is changed without - an equivalent change to a child class. + Deprecated alias to :class:`collections.abc.MappingView`. - For example: + .. deprecated:: 3.9 + :class:`collections.abc.MappingView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. testcode:: +.. class:: MutableMapping(Mapping[KT, VT]) - class Base: - def log_status(self) -> None: - ... + Deprecated alias to :class:`collections.abc.MutableMapping`. - class Sub(Base): - @override - def log_status(self) -> None: # Okay: overrides Base.log_status - ... + .. deprecated:: 3.9 + :class:`collections.abc.MutableMapping` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - @override - def done(self) -> None: # Error reported by type checker - ... +.. class:: MutableSequence(Sequence[T]) - There is no runtime checking of this property. + Deprecated alias to :class:`collections.abc.MutableSequence`. - The decorator will attempt to set an ``__override__`` attribute to ``True`` on - the decorated object. Thus, a check like - ``if getattr(obj, "__override__", False)`` can be used at runtime to determine - whether an object ``obj`` has been marked as an override. If the decorated object - does not support setting attributes, the decorator returns the object unchanged - without raising an exception. + .. deprecated:: 3.9 + :class:`collections.abc.MutableSequence` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - See :pep:`698` for more details. +.. class:: MutableSet(AbstractSet[T]) - .. versionadded:: 3.12 + Deprecated alias to :class:`collections.abc.MutableSet`. + + .. deprecated:: 3.9 + :class:`collections.abc.MutableSet` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. +.. class:: Sequence(Reversible[T_co], Collection[T_co]) -.. decorator:: type_check_only + Deprecated alias to :class:`collections.abc.Sequence`. - Decorator to mark a class or function as unavailable at runtime. + .. deprecated:: 3.9 + :class:`collections.abc.Sequence` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - This decorator is itself not available at runtime. It is mainly - intended to mark classes that are defined in type stub files if - an implementation returns an instance of a private class:: +.. class:: ValuesView(MappingView, Collection[_VT_co]) - @type_check_only - class Response: # private or not available at runtime - code: int - def get_header(self, name: str) -> str: ... + Deprecated alias to :class:`collections.abc.ValuesView`. - def fetch_response() -> Response: ... + .. deprecated:: 3.9 + :class:`collections.abc.ValuesView` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +Corresponding to other types in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" + +.. class:: Iterable(Generic[T_co]) + + Deprecated alias to :class:`collections.abc.Iterable`. + + .. deprecated:: 3.9 + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Note that returning instances of private classes is not recommended. - It is usually preferable to make such classes public. +.. class:: Iterator(Iterable[T_co]) -Introspection helpers ---------------------- + Deprecated alias to :class:`collections.abc.Iterator`. -.. function:: get_type_hints(obj, globalns=None, localns=None, include_extras=False) + .. deprecated:: 3.9 + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Return a dictionary containing type hints for a function, method, module - or class object. +.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) - This is often the same as ``obj.__annotations__``. In addition, - forward references encoded as string literals are handled by evaluating - them in ``globals`` and ``locals`` namespaces. For a class ``C``, return - a dictionary constructed by merging all the ``__annotations__`` along - ``C.__mro__`` in reverse order. + Deprecated alias to :class:`collections.abc.Generator`. - The function recursively replaces all ``Annotated[T, ...]`` with ``T``, - unless ``include_extras`` is set to ``True`` (see :class:`Annotated` for - more information). For example: + A generator can be annotated by the generic type + ``Generator[YieldType, SendType, ReturnType]``. For example:: - .. testcode:: + def echo_round() -> Generator[int, float, str]: + sent = yield 0 + while sent >= 0: + sent = yield round(sent) + return 'Done' - class Student(NamedTuple): - name: Annotated[str, 'some marker'] + Note that unlike many other generics in the typing module, the ``SendType`` + of :class:`Generator` behaves contravariantly, not covariantly or + invariantly. - assert get_type_hints(Student) == {'name': str} - assert get_type_hints(Student, include_extras=False) == {'name': str} - assert get_type_hints(Student, include_extras=True) == { - 'name': Annotated[str, 'some marker'] - } + If your generator will only yield values, set the ``SendType`` and + ``ReturnType`` to ``None``:: - .. note:: + def infinite_stream(start: int) -> Generator[int, None, None]: + while True: + yield start + start += 1 - :func:`get_type_hints` does not work with imported - :ref:`type aliases ` that include forward references. - Enabling postponed evaluation of annotations (:pep:`563`) may remove - the need for most forward references. + Alternatively, annotate your generator as having a return type of + either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: - .. versionchanged:: 3.9 - Added ``include_extras`` parameter as part of :pep:`593`. - See the documentation on :data:`Annotated` for more information. + def infinite_stream(start: int) -> Iterator[int]: + while True: + yield start + start += 1 - .. versionchanged:: 3.11 - Previously, ``Optional[t]`` was added for function and method annotations - if a default value equal to ``None`` was set. - Now the annotation is returned unchanged. + .. deprecated:: 3.9 + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -.. function:: get_origin(tp) +.. class:: Hashable - Get the unsubscripted version of a type: for a typing object of the form - ``X[Y, Z, ...]`` return ``X``. + Deprecated alias to :class:`collections.abc.Hashable`. - If ``X`` is a typing-module alias for a builtin or - :mod:`collections` class, it will be normalized to the original class. - If ``X`` is an instance of :class:`ParamSpecArgs` or :class:`ParamSpecKwargs`, - return the underlying :class:`ParamSpec`. - Return ``None`` for unsupported objects. + .. deprecated:: 3.12 + Use :class:`collections.abc.Hashable` directly instead. - Examples: +.. class:: Reversible(Iterable[T_co]) - .. testcode:: + Deprecated alias to :class:`collections.abc.Reversible`. - assert get_origin(str) is None - assert get_origin(Dict[str, int]) is dict - assert get_origin(Union[int, str]) is Union - P = ParamSpec('P') - assert get_origin(P.args) is P - assert get_origin(P.kwargs) is P + .. deprecated:: 3.9 + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - .. versionadded:: 3.8 +.. class:: Sized -.. function:: get_args(tp) + Deprecated alias to :class:`collections.abc.Sized`. - Get type arguments with all substitutions performed: for a typing object - of the form ``X[Y, Z, ...]`` return ``(Y, Z, ...)``. + .. deprecated:: 3.12 + Use :class:`collections.abc.Sized` directly instead. - If ``X`` is a union or :class:`Literal` contained in another - generic type, the order of ``(Y, Z, ...)`` may be different from the order - of the original arguments ``[Y, Z, ...]`` due to type caching. - Return ``()`` for unsupported objects. +Asynchronous programming +"""""""""""""""""""""""" - Examples: +.. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) - .. testcode:: + Deprecated alias to :class:`collections.abc.Coroutine`. - assert get_args(int) == () - assert get_args(Dict[int, str]) == (int, str) - assert get_args(Union[int, str]) == (int, str) + The variance and order of type variables + correspond to those of :class:`Generator`, for example:: - .. versionadded:: 3.8 + from collections.abc import Coroutine + c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere + x = c.send('hi') # Inferred type of 'x' is list[str] + async def bar() -> None: + y = await c # Inferred type of 'y' is int -.. function:: get_protocol_members(tp) + .. versionadded:: 3.5.3 - Return the set of members defined in a :class:`Protocol`. + .. deprecated:: 3.9 + :class:`collections.abc.Coroutine` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - :: +.. class:: AsyncGenerator(AsyncIterator[YieldType], Generic[YieldType, SendType]) - >>> from typing import Protocol, get_protocol_members - >>> class P(Protocol): - ... def a(self) -> str: ... - ... b: int - >>> get_protocol_members(P) - frozenset({'a', 'b'}) + Deprecated alias to :class:`collections.abc.AsyncGenerator`. - Raise :exc:`TypeError` for arguments that are not Protocols. + An async generator can be annotated by the generic type + ``AsyncGenerator[YieldType, SendType]``. For example:: - .. versionadded:: 3.13 + async def echo_round() -> AsyncGenerator[int, float]: + sent = yield 0 + while sent >= 0.0: + rounded = await round(sent) + sent = yield rounded -.. function:: is_protocol(tp) + Unlike normal generators, async generators cannot return a value, so there + is no ``ReturnType`` type parameter. As with :class:`Generator`, the + ``SendType`` behaves contravariantly. - Determine if a type is a :class:`Protocol`. + If your generator will only yield values, set the ``SendType`` to + ``None``:: - For example:: + async def infinite_stream(start: int) -> AsyncGenerator[int, None]: + while True: + yield start + start = await increment(start) - class P(Protocol): - def a(self) -> str: ... - b: int + Alternatively, annotate your generator as having a return type of + either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``:: - is_protocol(P) # => True - is_protocol(int) # => False + async def infinite_stream(start: int) -> AsyncIterator[int]: + while True: + yield start + start = await increment(start) - .. versionadded:: 3.13 + .. versionadded:: 3.6.1 -.. function:: is_typeddict(tp) + .. deprecated:: 3.9 + :class:`collections.abc.AsyncGenerator` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Check if a type is a :class:`TypedDict`. +.. class:: AsyncIterable(Generic[T_co]) - For example: + Deprecated alias to :class:`collections.abc.AsyncIterable`. - .. testcode:: + .. versionadded:: 3.5.2 - class Film(TypedDict): - title: str - year: int + .. deprecated:: 3.9 + :class:`collections.abc.AsyncIterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - assert is_typeddict(Film) - assert not is_typeddict(list | str) +.. class:: AsyncIterator(AsyncIterable[T_co]) - # TypedDict is a factory for creating typed dicts, - # not a typed dict itself - assert not is_typeddict(TypedDict) + Deprecated alias to :class:`collections.abc.AsyncIterator`. - .. versionadded:: 3.10 + .. versionadded:: 3.5.2 -.. class:: ForwardRef + .. deprecated:: 3.9 + :class:`collections.abc.AsyncIterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - Class used for internal typing representation of string forward references. +.. class:: Awaitable(Generic[T_co]) - For example, ``List["SomeClass"]`` is implicitly transformed into - ``List[ForwardRef("SomeClass")]``. ``ForwardRef`` should not be instantiated by - a user, but may be used by introspection tools. + Deprecated alias to :class:`collections.abc.Awaitable`. - .. note:: - :pep:`585` generic types such as ``list["SomeClass"]`` will not be - implicitly transformed into ``list[ForwardRef("SomeClass")]`` and thus - will not automatically resolve to ``list[SomeClass]``. + .. versionadded:: 3.5.2 - .. versionadded:: 3.7.4 + .. deprecated:: 3.9 + :class:`collections.abc.Awaitable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. -Constant --------- -.. data:: TYPE_CHECKING +Context manager types +""""""""""""""""""""" - A special constant that is assumed to be ``True`` by 3rd party static - type checkers. It is ``False`` at runtime. +.. class:: ContextManager(Generic[T_co]) - Usage:: + Deprecated alias to :class:`contextlib.AbstractContextManager`. - if TYPE_CHECKING: - import expensive_mod + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.0 - def fun(arg: 'expensive_mod.SomeType') -> None: - local_var: expensive_mod.AnotherType = other_fun() + .. deprecated:: 3.9 + :class:`contextlib.AbstractContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. - The first type annotation must be enclosed in quotes, making it a - "forward reference", to hide the ``expensive_mod`` reference from the - interpreter runtime. Type annotations for local variables are not - evaluated, so the second annotation does not need to be enclosed in quotes. +.. class:: AsyncContextManager(Generic[T_co]) - .. note:: + Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`. - If ``from __future__ import annotations`` is used, - annotations are not evaluated at function definition time. - Instead, they are stored as strings in ``__annotations__``. - This makes it unnecessary to use quotes around the annotation - (see :pep:`563`). + .. versionadded:: 3.5.4 + .. versionadded:: 3.6.2 - .. versionadded:: 3.5.2 + .. deprecated:: 3.9 + :class:`contextlib.AbstractAsyncContextManager` + now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. Deprecation Timeline of Major Features ====================================== From d32e8d6070057eb7ad0eb2f9d9f1efab38b2cff4 Mon Sep 17 00:00:00 2001 From: TATHAGATA ROY Date: Wed, 14 Jun 2023 19:51:30 +0530 Subject: [PATCH 042/446] gh-105196: Fix indentations of section headings in C API docs (#105672) --- Doc/c-api/float.rst | 8 ++++---- Doc/c-api/frame.rst | 2 +- Doc/c-api/slice.rst | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 05b2d100d575cb..0118bea4e720f8 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -3,7 +3,7 @@ .. _floatobjects: Floating Point Objects ----------------------- +====================== .. index:: pair: object; floating point @@ -79,7 +79,7 @@ Floating Point Objects Pack and Unpack functions -========================= +------------------------- The pack and unpack functions provide an efficient platform-independent way to store floating-point values as byte strings. The Pack routines produce a bytes @@ -104,7 +104,7 @@ happens in such cases is partly accidental (alas). .. versionadded:: 3.11 Pack functions --------------- +^^^^^^^^^^^^^^ The pack routines write 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if you want the bytes string in little-endian @@ -135,7 +135,7 @@ There are two problems on non-IEEE platforms: Unpack functions ----------------- +^^^^^^^^^^^^^^^^ The unpack routines read 2, 4 or 8 bytes, starting at *p*. *le* is an :c:expr:`int` argument, non-zero if the bytes string is in little-endian format diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 9f7addfbbf3cb4..1accee2767a485 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -134,7 +134,7 @@ See also :ref:`Reflection `. Internal Frames ---------------- +^^^^^^^^^^^^^^^ Unless using :pep:`523`, you will not need this. diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 8271d9acfb645e..33169ccce89043 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -113,7 +113,7 @@ Slice Objects Ellipsis Object ---------------- +^^^^^^^^^^^^^^^ .. c:var:: PyObject *Py_Ellipsis From 7b1f0f204a785485de1daf9d26828a81953537e4 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 14 Jun 2023 15:58:41 +0100 Subject: [PATCH 043/446] gh-105570: Deprecate unusual ways of creating empty TypedDicts (#105780) Deprecate two methods of creating typing.TypedDict classes with 0 fields using the functional syntax: `TD = TypedDict("TD")` and `TD = TypedDict("TD", None)`. Both will be disallowed in Python 3.15. To create a TypedDict class with 0 fields, either use `class TD(TypedDict): pass` or `TD = TypedDict("TD", {})`. --- Doc/library/typing.rst | 8 +++++ Doc/whatsnew/3.13.rst | 15 ++++---- Lib/test/test_typing.py | 34 +++++++++++++++++++ Lib/typing.py | 19 +++++++++-- ...-06-14-14-32-31.gh-issue-105570.sFTtQU.rst | 5 +++ 5 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-14-14-32-31.gh-issue-105570.sFTtQU.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 31861a0d613a88..73555d54115f3a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2388,6 +2388,14 @@ These are not used in annotations. They are building blocks for declaring types. .. versionchanged:: 3.13 Removed support for the keyword-argument method of creating ``TypedDict``\ s. + .. deprecated-removed:: 3.13 3.15 + When using the functional syntax to create a TypedDict class, failing to + pass a value to the 'fields' parameter (``TD = TypedDict("TD")``) is + deprecated. Passing ``None`` to the 'fields' parameter + (``TD = TypedDict("TD", None)``) is also deprecated. Both will be + disallowed in Python 3.15. To create a TypedDict class with 0 fields, + use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. + Protocols --------- diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index cf7c2ca24429d6..7f61ade808cce5 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -146,12 +146,15 @@ Deprecated be disallowed in Python 3.15. Use the class-based syntax or the functional syntax instead. (Contributed by Alex Waygood in :gh:`105566`.) * When using the functional syntax to create a :class:`typing.NamedTuple` - class, failing to pass a value to the 'fields' parameter - (``NT = NamedTuple("NT")``) is deprecated. Passing ``None`` to the 'fields' - parameter (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be - disallowed in Python 3.15. To create a NamedTuple class with 0 fields, use - ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. - (Contributed by Alex Waygood in :gh:`105566`.) + class or a :class:`typing.TypedDict` class, failing to pass a value to the + 'fields' parameter (``NT = NamedTuple("NT")`` or ``TD = TypedDict("TD")``) is + deprecated. Passing ``None`` to the 'fields' parameter + (``NT = NamedTuple("NT", None)`` or ``TD = TypedDict("TD", None)``) is also + deprecated. Both will be disallowed in Python 3.15. To create a NamedTuple + class with 0 fields, use ``class NT(NamedTuple): pass`` or + ``NT = NamedTuple("NT", [])``. To create a TypedDict class with 0 fields, use + ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. + (Contributed by Alex Waygood in :gh:`105566` and :gh:`105570`.) * :mod:`array`'s ``'u'`` format code, deprecated in docs since Python 3.3, emits :exc:`DeprecationWarning` since 3.13 diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 92f38043af5c03..3eb0fcad69e5e5 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7823,6 +7823,40 @@ class MultipleGenericBases(GenericParent[int], GenericParent[float]): self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float])) self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,)) + def test_zero_fields_typeddicts(self): + T1 = TypedDict("T1", {}) + class T2(TypedDict): pass + class T3[tvar](TypedDict): pass + S = TypeVar("S") + class T4(TypedDict, Generic[S]): pass + + expected_warning = re.escape( + "Failing to pass a value for the 'fields' parameter is deprecated " + "and will be disallowed in Python 3.15. " + "To create a TypedDict class with 0 fields " + "using the functional syntax, " + "pass an empty dictionary, e.g. `T5 = TypedDict('T5', {})`." + ) + with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): + T5 = TypedDict('T5') + + expected_warning = re.escape( + "Passing `None` as the 'fields' parameter is deprecated " + "and will be disallowed in Python 3.15. " + "To create a TypedDict class with 0 fields " + "using the functional syntax, " + "pass an empty dictionary, e.g. `T6 = TypedDict('T6', {})`." + ) + with self.assertWarnsRegex(DeprecationWarning, fr"^{expected_warning}$"): + T6 = TypedDict('T6', None) + + for klass in T1, T2, T3, T4, T5, T6: + with self.subTest(klass=klass.__name__): + self.assertEqual(klass.__annotations__, {}) + self.assertEqual(klass.__required_keys__, set()) + self.assertEqual(klass.__optional_keys__, set()) + self.assertIsInstance(klass(), dict) + class RequiredTests(BaseTestCase): diff --git a/Lib/typing.py b/Lib/typing.py index 570cb80cfeeb2c..1dd9398344639b 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2908,7 +2908,7 @@ def __subclasscheck__(cls, other): __instancecheck__ = __subclasscheck__ -def TypedDict(typename, fields=None, /, *, total=True): +def TypedDict(typename, fields=_sentinel, /, *, total=True): """A simple typed namespace. At runtime it is equivalent to a plain dict. TypedDict creates a dictionary type such that a type checker will expect all @@ -2955,7 +2955,22 @@ class Point2D(TypedDict): See PEP 655 for more details on Required and NotRequired. """ - if fields is None: + if fields is _sentinel or fields is None: + import warnings + + if fields is _sentinel: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + + example = f"`{typename} = TypedDict({typename!r}, {{{{}}}})`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a TypedDict class with 0 fields " + "using the functional syntax, " + "pass an empty dictionary, e.g. " + ) + example + "." + warnings._deprecated(deprecated_thing, message=deprecation_msg, remove=(3, 15)) fields = {} ns = {'__annotations__': dict(fields)} diff --git a/Misc/NEWS.d/next/Library/2023-06-14-14-32-31.gh-issue-105570.sFTtQU.rst b/Misc/NEWS.d/next/Library/2023-06-14-14-32-31.gh-issue-105570.sFTtQU.rst new file mode 100644 index 00000000000000..e31a8ee256d697 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-14-14-32-31.gh-issue-105570.sFTtQU.rst @@ -0,0 +1,5 @@ +Deprecate two methods of creating :class:`typing.TypedDict` classes with 0 +fields using the functional syntax: ``TD = TypedDict("TD")`` and +``TD = TypedDict("TD", None)``. Both will be disallowed in Python 3.15. To create a +``TypedDict`` class with 0 fields, either use ``class TD(TypedDict): pass`` +or ``TD = TypedDict("TD", {})``. From 307bceaa65c4f1a8e110cd7a9cce6e93a1b021ba Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 17:00:40 +0200 Subject: [PATCH 044/446] xmlrpc.client uses datetime.datetime.isoformat() (#105741) Reimplement _iso8601_format() using the datetime isoformat() method. Ignore the timezone. Co-Authored-by: Paul Ganssle <1377457+pganssle@users.noreply.github.com> --- Lib/test/test_xmlrpc.py | 6 ++++++ Lib/xmlrpc/client.py | 38 ++++++-------------------------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 9ff5545f786a32..edc741dbc60088 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -504,10 +504,16 @@ def test_time_struct(self): self.assertEqual(str(t), time.strftime("%Y%m%dT%H:%M:%S", d)) def test_datetime_datetime(self): + # naive (no tzinfo) d = datetime.datetime(2007,1,2,3,4,5) t = xmlrpclib.DateTime(d) self.assertEqual(str(t), '20070102T03:04:05') + # aware (with tzinfo): the timezone is ignored + d = datetime.datetime(2023, 6, 12, 13, 30, tzinfo=datetime.UTC) + t = xmlrpclib.DateTime(d) + self.assertEqual(str(t), '20230612T13:30:00') + def test_repr(self): d = datetime.datetime(2007,1,2,3,4,5) t = xmlrpclib.DateTime(d) diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index ea8da766cb5a7e..f441376d09c4aa 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -245,41 +245,15 @@ def __repr__(self): ## # Backwards compatibility - boolean = Boolean = bool -## -# Wrapper for XML-RPC DateTime values. This converts a time value to -# the format used by XML-RPC. -#

-# The value can be given as a datetime object, as a string in the -# format "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by -# time.localtime()), or an integer value (as returned by time.time()). -# The wrapper uses time.localtime() to convert an integer to a time -# tuple. -# -# @param value The time, given as a datetime object, an ISO 8601 string, -# a time tuple, or an integer time value. - -# Issue #13305: different format codes across platforms -_day0 = datetime(1, 1, 1) -def _try(fmt): - try: - return _day0.strftime(fmt) == '0001' - except ValueError: - return False -if _try('%Y'): # Mac OS X - def _iso8601_format(value): - return value.strftime("%Y%m%dT%H:%M:%S") -elif _try('%4Y'): # Linux - def _iso8601_format(value): - return value.strftime("%4Y%m%dT%H:%M:%S") -else: - def _iso8601_format(value): - return value.strftime("%Y%m%dT%H:%M:%S").zfill(17) -del _day0 -del _try +def _iso8601_format(value): + if value.tzinfo is not None: + # XML-RPC only uses the naive portion of the datetime + value = value.replace(tzinfo=None) + # XML-RPC doesn't use '-' separator in the date part + return value.isoformat(timespec='seconds').replace('-', '') def _strftime(value): From 1d857da7f0e4858e561223f319ae5afe737d5657 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 14 Jun 2023 16:15:08 +0100 Subject: [PATCH 045/446] GH-77273: Better bytecodes for f-strings (GH-6132) --- Doc/library/dis.rst | 53 +- Include/internal/pycore_opcode.h | 50 +- Include/opcode.h | 86 +-- Lib/dis.py | 19 +- Lib/importlib/_bootstrap_external.py | 6 +- Lib/opcode.py | 5 +- Lib/test/test_dis.py | 10 +- ...3-06-05-08-30-49.gh-issue-33092.hZ0xSI.rst | 3 + Programs/test_frozenmain.h | 4 +- Python/bytecodes.c | 54 +- Python/ceval.c | 8 + Python/compile.c | 28 +- Python/generated_cases.c.h | 610 +++++++++--------- Python/opcode_metadata.h | 18 +- Python/opcode_targets.h | 44 +- 15 files changed, 519 insertions(+), 479 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-05-08-30-49.gh-issue-33092.hZ0xSI.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 507b8299e7e75a..714dbc38f168ae 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1465,26 +1465,47 @@ iterations of the loop. an argument from two-byte to four-byte. -.. opcode:: FORMAT_VALUE (flags) +.. opcode:: CONVERT_VALUE (oparg) - Used for implementing formatted literal strings (f-strings). Pops - an optional *fmt_spec* from the stack, then a required *value*. - *flags* is interpreted as follows: + Convert value to a string, depending on ``oparg``:: - * ``(flags & 0x03) == 0x00``: *value* is formatted as-is. - * ``(flags & 0x03) == 0x01``: call :func:`str` on *value* before - formatting it. - * ``(flags & 0x03) == 0x02``: call :func:`repr` on *value* before - formatting it. - * ``(flags & 0x03) == 0x03``: call :func:`ascii` on *value* before - formatting it. - * ``(flags & 0x04) == 0x04``: pop *fmt_spec* from the stack and use - it, else use an empty *fmt_spec*. + value = STACK.pop() + result = func(value) + STACK.push(result) - Formatting is performed using :c:func:`PyObject_Format`. The - result is pushed on the stack. + * ``oparg == 1``: call :func:`str` on *value* + * ``oparg == 2``: call :func:`repr` on *value* + * ``oparg == 3``: call :func:`ascii` on *value* - .. versionadded:: 3.6 + Used for implementing formatted literal strings (f-strings). + + .. versionadded:: 3.13 + + +.. opcode:: FORMAT_SIMPLE + + Formats the value on top of stack:: + + value = STACK.pop() + result = value.__format__("") + STACK.push(result) + + Used for implementing formatted literal strings (f-strings). + + .. versionadded:: 3.13 + +.. opcode:: FORMAT_SPEC + + Formats the given value with the given format spec:: + + spec = STACK.pop() + value = STACK.pop() + result = value.__format__(spec) + STACK.push(result) + + Used for implementing formatted literal strings (f-strings). + + .. versionadded:: 3.13 .. opcode:: MATCH_CLASS (count) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index d706b85b6e43f7..d680039e5eed96 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -102,6 +102,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [COMPARE_OP_INT] = COMPARE_OP, [COMPARE_OP_STR] = COMPARE_OP, [CONTAINS_OP] = CONTAINS_OP, + [CONVERT_VALUE] = CONVERT_VALUE, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, [DELETE_ATTR] = DELETE_ATTR, @@ -117,7 +118,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [END_SEND] = END_SEND, [ENTER_EXECUTOR] = ENTER_EXECUTOR, [EXTENDED_ARG] = EXTENDED_ARG, - [FORMAT_VALUE] = FORMAT_VALUE, + [FORMAT_SIMPLE] = FORMAT_SIMPLE, + [FORMAT_WITH_SPEC] = FORMAT_WITH_SPEC, [FOR_ITER] = FOR_ITER, [FOR_ITER_GEN] = FOR_ITER, [FOR_ITER_LIST] = FOR_ITER, @@ -286,6 +288,8 @@ static const char *const _PyOpcode_OpName[267] = { [CHECK_EG_MATCH] = "CHECK_EG_MATCH", [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [FORMAT_SIMPLE] = "FORMAT_SIMPLE", + [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC", [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", @@ -293,8 +297,6 @@ static const char *const _PyOpcode_OpName[267] = { [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", - [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -302,39 +304,39 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", - [COMPARE_OP_INT] = "COMPARE_OP_INT", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", + [COMPARE_OP_INT] = "COMPARE_OP_INT", [COMPARE_OP_STR] = "COMPARE_OP_STR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [FOR_ITER_GEN] = "FOR_ITER_GEN", - [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", + [FOR_ITER_GEN] = "FOR_ITER_GEN", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", + [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_LOCALS] = "LOAD_LOCALS", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -357,9 +359,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -378,7 +380,7 @@ static const char *const _PyOpcode_OpName[267] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", @@ -394,20 +396,20 @@ static const char *const _PyOpcode_OpName[267] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [CONVERT_VALUE] = "CONVERT_VALUE", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", - [160] = "<160>", - [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", @@ -517,8 +519,6 @@ static const char *const _PyOpcode_OpName[267] = { #endif #define EXTRA_CASES \ - case 160: \ - case 161: \ case 166: \ case 167: \ case 178: \ diff --git a/Include/opcode.h b/Include/opcode.h index be538999d1496f..c6ffaee3522142 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -30,6 +30,8 @@ extern "C" { #define PUSH_EXC_INFO 35 #define CHECK_EXC_MATCH 36 #define CHECK_EG_MATCH 37 +#define FORMAT_SIMPLE 40 +#define FORMAT_WITH_SPEC 41 #define WITH_EXCEPT_START 49 #define GET_AITER 50 #define GET_ANEXT 51 @@ -107,9 +109,9 @@ extern "C" { #define YIELD_VALUE 150 #define RESUME 151 #define MATCH_CLASS 152 -#define FORMAT_VALUE 155 #define BUILD_CONST_KEY_MAP 156 #define BUILD_STRING 157 +#define CONVERT_VALUE 158 #define LIST_EXTEND 162 #define SET_UPDATE 163 #define DICT_MERGE 164 @@ -175,47 +177,47 @@ extern "C" { #define CALL_BUILTIN_CLASS 34 #define CALL_BUILTIN_FAST_WITH_KEYWORDS 38 #define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 39 -#define CALL_NO_KW_BUILTIN_FAST 40 -#define CALL_NO_KW_BUILTIN_O 41 -#define CALL_NO_KW_ISINSTANCE 42 -#define CALL_NO_KW_LEN 43 -#define CALL_NO_KW_LIST_APPEND 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 46 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 47 -#define CALL_NO_KW_STR_1 48 -#define CALL_NO_KW_TUPLE_1 56 -#define CALL_NO_KW_TYPE_1 57 -#define COMPARE_OP_FLOAT 58 -#define COMPARE_OP_INT 59 -#define COMPARE_OP_STR 62 -#define FOR_ITER_LIST 63 -#define FOR_ITER_TUPLE 64 -#define FOR_ITER_RANGE 65 -#define FOR_ITER_GEN 66 -#define LOAD_SUPER_ATTR_ATTR 67 -#define LOAD_SUPER_ATTR_METHOD 70 -#define LOAD_ATTR_CLASS 72 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 -#define LOAD_ATTR_INSTANCE_VALUE 76 -#define LOAD_ATTR_MODULE 77 -#define LOAD_ATTR_PROPERTY 78 -#define LOAD_ATTR_SLOT 79 -#define LOAD_ATTR_WITH_HINT 80 -#define LOAD_ATTR_METHOD_LAZY_DICT 81 -#define LOAD_ATTR_METHOD_NO_DICT 82 -#define LOAD_ATTR_METHOD_WITH_VALUES 84 -#define LOAD_GLOBAL_BUILTIN 86 -#define LOAD_GLOBAL_MODULE 88 -#define STORE_ATTR_INSTANCE_VALUE 111 -#define STORE_ATTR_SLOT 112 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_SUBSCR_DICT 132 -#define STORE_SUBSCR_LIST_INT 148 -#define UNPACK_SEQUENCE_LIST 153 -#define UNPACK_SEQUENCE_TUPLE 154 -#define UNPACK_SEQUENCE_TWO_TUPLE 158 -#define SEND_GEN 159 +#define CALL_NO_KW_BUILTIN_FAST 42 +#define CALL_NO_KW_BUILTIN_O 43 +#define CALL_NO_KW_ISINSTANCE 44 +#define CALL_NO_KW_LEN 45 +#define CALL_NO_KW_LIST_APPEND 46 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 47 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 48 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 56 +#define CALL_NO_KW_STR_1 57 +#define CALL_NO_KW_TUPLE_1 58 +#define CALL_NO_KW_TYPE_1 59 +#define COMPARE_OP_FLOAT 62 +#define COMPARE_OP_INT 63 +#define COMPARE_OP_STR 64 +#define FOR_ITER_LIST 65 +#define FOR_ITER_TUPLE 66 +#define FOR_ITER_RANGE 67 +#define FOR_ITER_GEN 70 +#define LOAD_SUPER_ATTR_ATTR 72 +#define LOAD_SUPER_ATTR_METHOD 73 +#define LOAD_ATTR_CLASS 76 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 77 +#define LOAD_ATTR_INSTANCE_VALUE 78 +#define LOAD_ATTR_MODULE 79 +#define LOAD_ATTR_PROPERTY 80 +#define LOAD_ATTR_SLOT 81 +#define LOAD_ATTR_WITH_HINT 82 +#define LOAD_ATTR_METHOD_LAZY_DICT 84 +#define LOAD_ATTR_METHOD_NO_DICT 86 +#define LOAD_ATTR_METHOD_WITH_VALUES 88 +#define LOAD_GLOBAL_BUILTIN 111 +#define LOAD_GLOBAL_MODULE 112 +#define STORE_ATTR_INSTANCE_VALUE 113 +#define STORE_ATTR_SLOT 132 +#define STORE_ATTR_WITH_HINT 148 +#define STORE_SUBSCR_DICT 153 +#define STORE_SUBSCR_LIST_INT 154 +#define UNPACK_SEQUENCE_LIST 155 +#define UNPACK_SEQUENCE_TUPLE 159 +#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define SEND_GEN 161 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/dis.py b/Lib/dis.py index dd5ad41dc3295f..f135a0bc9b4d98 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -25,13 +25,8 @@ _have_code = (types.MethodType, types.FunctionType, types.CodeType, classmethod, staticmethod, type) -FORMAT_VALUE = opmap['FORMAT_VALUE'] -FORMAT_VALUE_CONVERTERS = ( - (None, ''), - (str, 'str'), - (repr, 'repr'), - (ascii, 'ascii'), -) +CONVERT_VALUE = opmap['CONVERT_VALUE'] + SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE'] FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure') @@ -579,13 +574,9 @@ def _get_instructions_bytes(code, varname_from_oparg=None, elif deop in hascompare: argval = cmp_op[arg>>4] argrepr = argval - elif deop == FORMAT_VALUE: - argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3] - argval = (argval, bool(arg & 0x4)) - if argval[1]: - if argrepr: - argrepr += ', ' - argrepr += 'with format' + elif deop == CONVERT_VALUE: + argval = (None, str, repr, ascii)[arg] + argrepr = ('', 'str', 'repr', 'ascii')[arg] elif deop == SET_FUNCTION_ATTRIBUTE: argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS) if arg & (1<= FVC_STR && oparg <= FVC_ASCII); + conv_fn = CONVERSION_FUNCTIONS[oparg]; + result = conv_fn(value); + Py_DECREF(value); + ERROR_IF(result == NULL, error); + } - /* If there's a conversion function, call it and replace - value with that result. Otherwise, just use value, - without conversion. */ - if (conv_fn != NULL) { - result = conv_fn(value); + inst(FORMAT_SIMPLE, (value -- res)) { + /* If value is a unicode object, then we know the result + * of format(value) is value itself. */ + if (!PyUnicode_CheckExact(value)) { + res = PyObject_Format(value, NULL); Py_DECREF(value); - if (result == NULL) { - Py_XDECREF(fmt_spec); - ERROR_IF(true, error); - } - value = result; + ERROR_IF(res == NULL, error); } + else { + res = value; + } + } - result = PyObject_Format(value, fmt_spec); + inst(FORMAT_WITH_SPEC, (value, fmt_spec -- res)) { + res = PyObject_Format(value, fmt_spec); Py_DECREF(value); - Py_XDECREF(fmt_spec); - ERROR_IF(result == NULL, error); + Py_DECREF(fmt_spec); + ERROR_IF(res == NULL, error); } inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { diff --git a/Python/ceval.c b/Python/ceval.c index 54ef03702f7006..b628190fcd57ac 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -222,6 +222,14 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, static void _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); +typedef PyObject *(*convertion_func_ptr)(PyObject *); + +static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = { + [FVC_STR] = PyObject_Str, + [FVC_REPR] = PyObject_Repr, + [FVC_ASCII] = PyObject_ASCII +}; + #define UNBOUNDLOCAL_ERROR_MSG \ "cannot access local variable '%s' where it is not associated with a value" #define UNBOUNDFREE_ERROR_MSG \ diff --git a/Python/compile.c b/Python/compile.c index 399a702ac1d7eb..daeb4dbeed987e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4985,26 +4985,26 @@ compiler_formatted_value(struct compiler *c, expr_ty e) /* The expression to be formatted. */ VISIT(c, expr, e->v.FormattedValue.value); - switch (conversion) { - case 's': oparg = FVC_STR; break; - case 'r': oparg = FVC_REPR; break; - case 'a': oparg = FVC_ASCII; break; - case -1: oparg = FVC_NONE; break; - default: - PyErr_Format(PyExc_SystemError, + location loc = LOC(e); + if (conversion != -1) { + switch (conversion) { + case 's': oparg = FVC_STR; break; + case 'r': oparg = FVC_REPR; break; + case 'a': oparg = FVC_ASCII; break; + default: + PyErr_Format(PyExc_SystemError, "Unrecognized conversion character %d", conversion); - return ERROR; + return ERROR; + } + ADDOP_I(c, loc, CONVERT_VALUE, oparg); } if (e->v.FormattedValue.format_spec) { /* Evaluate the format spec, and update our opcode arg. */ VISIT(c, expr, e->v.FormattedValue.format_spec); - oparg |= FVS_HAVE_SPEC; + ADDOP(c, loc, FORMAT_WITH_SPEC); + } else { + ADDOP(c, loc, FORMAT_SIMPLE); } - - /* And push our opcode and oparg */ - location loc = LOC(e); - ADDOP_I(c, loc, FORMAT_VALUE, oparg); - return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 008524ac95b69b..8e3f925a2a655a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 137 "Python/bytecodes.c" + #line 139 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 151 "Python/bytecodes.c" + #line 153 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? @@ -57,7 +57,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 179 "Python/bytecodes.c" + #line 181 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -70,7 +70,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 186 "Python/bytecodes.c" + #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -82,7 +82,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 194 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 200 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -107,7 +107,7 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 204 "Python/bytecodes.c" + #line 206 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); @@ -123,7 +123,7 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 213 "Python/bytecodes.c" + #line 215 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 130 "Python/generated_cases.c.h" @@ -134,7 +134,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 218 "Python/bytecodes.c" + #line 220 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 140 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -144,7 +144,7 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 226 "Python/bytecodes.c" + #line 228 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -158,7 +158,7 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 234 "Python/bytecodes.c" + #line 236 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -170,7 +170,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 241 "Python/bytecodes.c" + #line 243 "Python/bytecodes.c" #line 175 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -179,7 +179,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 245 "Python/bytecodes.c" + #line 247 "Python/bytecodes.c" res = NULL; #line 185 "Python/generated_cases.c.h" STACK_GROW(1); @@ -192,13 +192,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 241 "Python/bytecodes.c" + #line 243 "Python/bytecodes.c" #line 197 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 241 "Python/bytecodes.c" + #line 243 "Python/bytecodes.c" #line 203 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -209,7 +209,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 251 "Python/bytecodes.c" + #line 253 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -229,7 +229,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 264 "Python/bytecodes.c" + #line 266 "Python/bytecodes.c" Py_DECREF(receiver); #line 235 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -240,7 +240,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 268 "Python/bytecodes.c" + #line 270 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -258,11 +258,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 279 "Python/bytecodes.c" + #line 281 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 264 "Python/generated_cases.c.h" Py_DECREF(value); - #line 281 "Python/bytecodes.c" + #line 283 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 268 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -272,11 +272,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 285 "Python/bytecodes.c" + #line 287 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 278 "Python/generated_cases.c.h" Py_DECREF(value); - #line 287 "Python/bytecodes.c" + #line 289 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -292,11 +292,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 297 "Python/bytecodes.c" + #line 299 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 298 "Python/generated_cases.c.h" Py_DECREF(value); - #line 299 "Python/bytecodes.c" + #line 301 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 302 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -309,7 +309,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 317 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 316 "Python/generated_cases.c.h" @@ -320,7 +320,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 320 "Python/bytecodes.c" + #line 322 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -341,7 +341,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 317 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 348 "Python/generated_cases.c.h" @@ -352,7 +352,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 328 "Python/bytecodes.c" + #line 330 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -373,7 +373,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 317 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 380 "Python/generated_cases.c.h" @@ -384,7 +384,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 336 "Python/bytecodes.c" + #line 338 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -405,7 +405,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 353 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 412 "Python/generated_cases.c.h" @@ -416,7 +416,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 356 "Python/bytecodes.c" + #line 358 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -437,7 +437,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 353 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 444 "Python/generated_cases.c.h" @@ -448,7 +448,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 364 "Python/bytecodes.c" + #line 366 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -469,7 +469,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 353 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 476 "Python/generated_cases.c.h" @@ -480,7 +480,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 372 "Python/bytecodes.c" + #line 374 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -501,7 +501,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 389 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 508 "Python/generated_cases.c.h" @@ -512,7 +512,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 392 "Python/bytecodes.c" + #line 394 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -533,7 +533,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 389 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 540 "Python/generated_cases.c.h" @@ -543,7 +543,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 409 "Python/bytecodes.c" + #line 411 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -579,7 +579,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 446 "Python/bytecodes.c" + #line 448 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -594,7 +594,7 @@ #line 595 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 458 "Python/bytecodes.c" + #line 460 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 600 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -608,7 +608,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 462 "Python/bytecodes.c" + #line 464 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -632,7 +632,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 477 "Python/bytecodes.c" + #line 479 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -654,7 +654,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 492 "Python/bytecodes.c" + #line 494 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -679,7 +679,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 508 "Python/bytecodes.c" + #line 510 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -704,7 +704,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 524 "Python/bytecodes.c" + #line 526 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -715,7 +715,7 @@ #line 716 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 532 "Python/bytecodes.c" + #line 534 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -731,7 +731,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 539 "Python/bytecodes.c" + #line 541 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -760,7 +760,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 564 "Python/bytecodes.c" + #line 566 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -770,11 +770,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 568 "Python/bytecodes.c" + #line 570 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 776 "Python/generated_cases.c.h" Py_DECREF(v); - #line 570 "Python/bytecodes.c" + #line 572 "Python/bytecodes.c" if (err) goto pop_1_error; #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -788,7 +788,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 580 "Python/bytecodes.c" + #line 582 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -807,7 +807,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 595 "Python/bytecodes.c" + #line 597 "Python/bytecodes.c" if (err) goto pop_3_error; #line 813 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -819,7 +819,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 599 "Python/bytecodes.c" + #line 601 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -846,7 +846,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 618 "Python/bytecodes.c" + #line 620 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -861,13 +861,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 626 "Python/bytecodes.c" + #line 628 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 868 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 629 "Python/bytecodes.c" + #line 631 "Python/bytecodes.c" if (err) goto pop_2_error; #line 873 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -877,12 +877,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 633 "Python/bytecodes.c" + #line 635 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 884 "Python/generated_cases.c.h" Py_DECREF(value); - #line 636 "Python/bytecodes.c" + #line 638 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 888 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -893,13 +893,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 640 "Python/bytecodes.c" + #line 642 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 900 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 643 "Python/bytecodes.c" + #line 645 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 905 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -909,7 +909,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 647 "Python/bytecodes.c" + #line 649 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -932,7 +932,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 667 "Python/bytecodes.c" + #line 669 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -946,7 +946,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 678 "Python/bytecodes.c" + #line 680 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -964,7 +964,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 693 "Python/bytecodes.c" + #line 695 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -985,7 +985,7 @@ } TARGET(RETURN_CONST) { - #line 712 "Python/bytecodes.c" + #line 714 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1003,7 +1003,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 728 "Python/bytecodes.c" + #line 730 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1027,7 +1027,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 748 "Python/bytecodes.c" + #line 750 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1042,14 +1042,14 @@ type->tp_name); #line 1044 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 761 "Python/bytecodes.c" + #line 763 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1051 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 766 "Python/bytecodes.c" + #line 768 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1070,7 +1070,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 781 "Python/bytecodes.c" + #line 783 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1122,7 +1122,7 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 826 "Python/bytecodes.c" + #line 828 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1131,7 +1131,7 @@ #line 1133 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 833 "Python/bytecodes.c" + #line 835 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1159,7 +1159,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 857 "Python/bytecodes.c" + #line 859 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1215,7 +1215,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 906 "Python/bytecodes.c" + #line 908 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1236,7 +1236,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 924 "Python/bytecodes.c" + #line 926 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1259,7 +1259,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 944 "Python/bytecodes.c" + #line 946 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1281,7 +1281,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 963 "Python/bytecodes.c" + #line 965 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1288 "Python/generated_cases.c.h" @@ -1292,7 +1292,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 968 "Python/bytecodes.c" + #line 970 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1316,13 +1316,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 988 "Python/bytecodes.c" + #line 990 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1323 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 991 "Python/bytecodes.c" + #line 993 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1340,7 +1340,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1000 "Python/bytecodes.c" + #line 1002 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1349,7 +1349,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1005 "Python/bytecodes.c" + #line 1007 "Python/bytecodes.c" none = Py_None; } else { @@ -1365,7 +1365,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1014 "Python/bytecodes.c" + #line 1016 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1371 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1375,7 +1375,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1018 "Python/bytecodes.c" + #line 1020 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1405,7 +1405,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1043 "Python/bytecodes.c" + #line 1045 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1414,7 +1414,7 @@ "no locals found when storing %R", name); #line 1416 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1050 "Python/bytecodes.c" + #line 1052 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1423,7 +1423,7 @@ err = PyObject_SetItem(ns, name, v); #line 1425 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1057 "Python/bytecodes.c" + #line 1059 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1429 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1431,7 +1431,7 @@ } TARGET(DELETE_NAME) { - #line 1061 "Python/bytecodes.c" + #line 1063 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1456,7 +1456,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1087 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1471,7 +1471,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1100 "Python/bytecodes.c" + #line 1102 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1477 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1483,7 +1483,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1104 "Python/bytecodes.c" + #line 1106 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1501,7 +1501,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1114 "Python/bytecodes.c" + #line 1116 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1520,7 +1520,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1125 "Python/bytecodes.c" + #line 1127 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1538,13 +1538,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1136 "Python/bytecodes.c" + #line 1138 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1546 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1140 "Python/bytecodes.c" + #line 1142 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1550 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1557,7 +1557,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1151 "Python/bytecodes.c" + #line 1153 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1576,7 +1576,7 @@ #line 1577 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1167 "Python/bytecodes.c" + #line 1169 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1582 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1586,12 +1586,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1171 "Python/bytecodes.c" + #line 1173 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1593 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1174 "Python/bytecodes.c" + #line 1176 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1597 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1600,12 +1600,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1178 "Python/bytecodes.c" + #line 1180 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1607 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1181 "Python/bytecodes.c" + #line 1183 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1611 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1613,7 +1613,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1185 "Python/bytecodes.c" + #line 1187 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1633,7 +1633,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1201 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1653,7 +1653,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1201 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1667,7 +1667,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" + #line 1213 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1737,7 +1737,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" + #line 1213 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1806,7 +1806,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1280 "Python/bytecodes.c" + #line 1282 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1872,7 +1872,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1334 "Python/bytecodes.c" + #line 1336 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1898,7 +1898,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1347 "Python/bytecodes.c" + #line 1349 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1923,7 +1923,7 @@ } TARGET(DELETE_FAST) { - #line 1364 "Python/bytecodes.c" + #line 1366 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1932,7 +1932,7 @@ } TARGET(MAKE_CELL) { - #line 1370 "Python/bytecodes.c" + #line 1372 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1946,7 +1946,7 @@ } TARGET(DELETE_DEREF) { - #line 1381 "Python/bytecodes.c" + #line 1383 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1964,7 +1964,7 @@ TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1394 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -2006,7 +2006,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1431 "Python/bytecodes.c" + #line 1433 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2022,7 +2022,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1441 "Python/bytecodes.c" + #line 1443 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -2033,7 +2033,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1448 "Python/bytecodes.c" + #line 1450 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2051,13 +2051,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1461 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2057 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1463 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2069,7 +2069,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1467 "Python/bytecodes.c" + #line 1469 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2076 "Python/generated_cases.c.h" @@ -2082,7 +2082,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1472 "Python/bytecodes.c" + #line 1474 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2089 "Python/generated_cases.c.h" @@ -2095,7 +2095,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1477 "Python/bytecodes.c" + #line 1479 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2108,7 +2108,7 @@ } #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1488 "Python/bytecodes.c" + #line 1490 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -2121,11 +2121,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1495 "Python/bytecodes.c" + #line 1497 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2127 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1497 "Python/bytecodes.c" + #line 1499 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2131 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2135,7 +2135,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1501 "Python/bytecodes.c" + #line 1503 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2160,7 +2160,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1518 "Python/bytecodes.c" + #line 1520 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2172,7 +2172,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1526 "Python/bytecodes.c" + #line 1528 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -2182,7 +2182,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1530 "Python/bytecodes.c" + #line 1532 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2230,7 +2230,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1572 "Python/bytecodes.c" + #line 1574 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2245,7 +2245,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1582 "Python/bytecodes.c" + #line 1584 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2255,7 +2255,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1586 "Python/bytecodes.c" + #line 1588 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2265,7 +2265,7 @@ } #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1594 "Python/bytecodes.c" + #line 1596 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2272 "Python/generated_cases.c.h" @@ -2276,14 +2276,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1600 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2285 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1605 "Python/bytecodes.c" + #line 1607 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2290 "Python/generated_cases.c.h" @@ -2295,7 +2295,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1611 "Python/bytecodes.c" + #line 1613 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2307,7 +2307,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1619 "Python/bytecodes.c" + #line 1621 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -2324,7 +2324,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1633 "Python/bytecodes.c" + #line 1635 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2370,7 +2370,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1675 "Python/bytecodes.c" + #line 1677 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2390,7 +2390,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1694 "Python/bytecodes.c" + #line 1696 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2401,7 +2401,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1701 "Python/bytecodes.c" + #line 1703 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2407 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -2418,7 +2418,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1707 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2455,7 +2455,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1744 "Python/bytecodes.c" + #line 1746 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2491,7 +2491,7 @@ */ #line 2493 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1778 "Python/bytecodes.c" + #line 1780 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2502,7 +2502,7 @@ res = PyObject_GetAttr(owner, name); #line 2504 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1787 "Python/bytecodes.c" + #line 1789 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2509 "Python/generated_cases.c.h" @@ -2519,7 +2519,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1796 "Python/bytecodes.c" + #line 1798 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2547,7 +2547,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1812 "Python/bytecodes.c" + #line 1814 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2575,7 +2575,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1828 "Python/bytecodes.c" + #line 1830 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2617,7 +2617,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1858 "Python/bytecodes.c" + #line 1860 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2642,7 +2642,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1871 "Python/bytecodes.c" + #line 1873 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2668,7 +2668,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1886 "Python/bytecodes.c" + #line 1888 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2700,7 +2700,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1912 "Python/bytecodes.c" + #line 1914 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2734,7 +2734,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1940 "Python/bytecodes.c" + #line 1942 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2763,7 +2763,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1960 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2813,7 +2813,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2001 "Python/bytecodes.c" + #line 2003 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2835,7 +2835,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2020 "Python/bytecodes.c" + #line 2022 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2851,7 +2851,7 @@ #line 2852 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2033 "Python/bytecodes.c" + #line 2035 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2857 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2864,7 +2864,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2037 "Python/bytecodes.c" + #line 2039 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2886,7 +2886,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2051 "Python/bytecodes.c" + #line 2053 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2912,7 +2912,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2069 "Python/bytecodes.c" + #line 2071 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2935,12 +2935,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2083 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2941 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2085 "Python/bytecodes.c" + #line 2087 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2952,12 +2952,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2089 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2958 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2091 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 2964 "Python/generated_cases.c.h" @@ -2971,12 +2971,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2096 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2977 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2098 "Python/bytecodes.c" + #line 2100 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2987,7 +2987,7 @@ #line 2988 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2106 "Python/bytecodes.c" + #line 2108 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3006,19 +3006,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2117 "Python/bytecodes.c" + #line 2119 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3013 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2120 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3020 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2125 "Python/bytecodes.c" + #line 2127 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3024 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3029,13 +3029,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2129 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3036 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2132 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3046,7 +3046,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2136 "Python/bytecodes.c" + #line 2138 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3057,14 +3057,14 @@ } TARGET(JUMP_FORWARD) { - #line 2142 "Python/bytecodes.c" + #line 2144 "Python/bytecodes.c" JUMPBY(oparg); #line 3063 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2146 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3087,7 +3087,7 @@ } TARGET(ENTER_EXECUTOR) { - #line 2176 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg]; Py_INCREF(executor); @@ -3102,7 +3102,7 @@ TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2188 "Python/bytecodes.c" + #line 2190 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } @@ -3110,7 +3110,7 @@ int err = PyObject_IsTrue(cond); #line 3112 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2194 "Python/bytecodes.c" + #line 2196 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3125,7 +3125,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2204 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } @@ -3133,7 +3133,7 @@ int err = PyObject_IsTrue(cond); #line 3135 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2210 "Python/bytecodes.c" + #line 2212 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3148,11 +3148,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2220 "Python/bytecodes.c" + #line 2222 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3154 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2222 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" JUMPBY(oparg); } #line 3159 "Python/generated_cases.c.h" @@ -3162,14 +3162,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2227 "Python/bytecodes.c" + #line 2229 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3171 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2232 "Python/bytecodes.c" + #line 2234 "Python/bytecodes.c" } #line 3175 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3177,7 +3177,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2236 "Python/bytecodes.c" + #line 2238 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3191,7 +3191,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2245 "Python/bytecodes.c" + #line 2247 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3208,7 +3208,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2253 "Python/bytecodes.c" + #line 2255 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3217,7 +3217,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2258 "Python/bytecodes.c" + #line 2260 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3234,7 +3234,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2268 "Python/bytecodes.c" + #line 2270 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3241 "Python/generated_cases.c.h" @@ -3246,7 +3246,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2273 "Python/bytecodes.c" + #line 2275 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3253 "Python/generated_cases.c.h" @@ -3259,7 +3259,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2278 "Python/bytecodes.c" + #line 2280 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -3272,12 +3272,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2284 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3279 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2287 "Python/bytecodes.c" + #line 2289 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3283 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3287,7 +3287,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2291 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3312,7 +3312,7 @@ } #line 3314 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2314 "Python/bytecodes.c" + #line 2316 "Python/bytecodes.c" } #line 3318 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3324,7 +3324,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2332 "Python/bytecodes.c" + #line 2334 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3363,7 +3363,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2365 "Python/bytecodes.c" + #line 2367 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3396,7 +3396,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2393 "Python/bytecodes.c" + #line 2395 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3426,7 +3426,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2415 "Python/bytecodes.c" + #line 2417 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3456,7 +3456,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2437 "Python/bytecodes.c" + #line 2439 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3483,7 +3483,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2457 "Python/bytecodes.c" + #line 2459 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3506,7 +3506,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2475 "Python/bytecodes.c" + #line 2477 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3531,7 +3531,7 @@ } #line 3533 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2498 "Python/bytecodes.c" + #line 2500 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3549,7 +3549,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2507 "Python/bytecodes.c" + #line 2509 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3577,7 +3577,7 @@ } #line 3579 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2533 "Python/bytecodes.c" + #line 2535 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3596,7 +3596,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2542 "Python/bytecodes.c" + #line 2544 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3626,7 +3626,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2581 "Python/bytecodes.c" + #line 2583 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3650,7 +3650,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2593 "Python/bytecodes.c" + #line 2595 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3681,7 +3681,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2612 "Python/bytecodes.c" + #line 2614 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3705,7 +3705,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2624 "Python/bytecodes.c" + #line 2626 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3728,7 +3728,7 @@ } TARGET(KW_NAMES) { - #line 2640 "Python/bytecodes.c" + #line 2642 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); @@ -3737,7 +3737,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2646 "Python/bytecodes.c" + #line 2648 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3760,7 +3760,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2691 "Python/bytecodes.c" + #line 2693 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3854,7 +3854,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2779 "Python/bytecodes.c" + #line 2781 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3873,7 +3873,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2791 "Python/bytecodes.c" + #line 2793 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3907,7 +3907,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2819 "Python/bytecodes.c" + #line 2821 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3951,7 +3951,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2857 "Python/bytecodes.c" + #line 2859 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3974,7 +3974,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2869 "Python/bytecodes.c" + #line 2871 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3999,7 +3999,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2883 "Python/bytecodes.c" + #line 2885 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4024,7 +4024,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2897 "Python/bytecodes.c" + #line 2899 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4060,7 +4060,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2922 "Python/bytecodes.c" + #line 2924 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4102,7 +4102,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2953 "Python/bytecodes.c" + #line 2955 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4148,7 +4148,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2988 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4194,7 +4194,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3023 "Python/bytecodes.c" + #line 3025 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4232,7 +4232,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3050 "Python/bytecodes.c" + #line 3052 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4271,7 +4271,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3080 "Python/bytecodes.c" + #line 3082 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4296,7 +4296,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3100 "Python/bytecodes.c" + #line 3102 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4340,7 +4340,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3134 "Python/bytecodes.c" + #line 3136 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4382,7 +4382,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3166 "Python/bytecodes.c" + #line 3168 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4424,7 +4424,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3198 "Python/bytecodes.c" + #line 3200 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4462,7 +4462,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3229 "Python/bytecodes.c" + #line 3231 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4468 "Python/generated_cases.c.h" } @@ -4473,7 +4473,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3233 "Python/bytecodes.c" + #line 3235 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4539,7 +4539,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3295 "Python/bytecodes.c" + #line 3297 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4546 "Python/generated_cases.c.h" @@ -4553,7 +4553,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3301 "Python/bytecodes.c" + #line 3303 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4573,7 +4573,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3315 "Python/bytecodes.c" + #line 3317 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4605,7 +4605,7 @@ } TARGET(RETURN_GENERATOR) { - #line 3342 "Python/bytecodes.c" + #line 3344 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4634,13 +4634,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3365 "Python/bytecodes.c" + #line 3367 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4640 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3367 "Python/bytecodes.c" + #line 3369 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4646 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4649,58 +4649,62 @@ DISPATCH(); } - TARGET(FORMAT_VALUE) { - PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; - PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; + TARGET(CONVERT_VALUE) { + PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3371 "Python/bytecodes.c" - /* Handles f-string value formatting. */ - PyObject *(*conv_fn)(PyObject *); - int which_conversion = oparg & FVC_MASK; - - /* See if any conversion is specified. */ - switch (which_conversion) { - case FVC_NONE: conv_fn = NULL; break; - case FVC_STR: conv_fn = PyObject_Str; break; - case FVC_REPR: conv_fn = PyObject_Repr; break; - case FVC_ASCII: conv_fn = PyObject_ASCII; break; - default: - _PyErr_Format(tstate, PyExc_SystemError, - "unexpected conversion flag %d", - which_conversion); - goto error; - } + #line 3373 "Python/bytecodes.c" + convertion_func_ptr conv_fn; + assert(oparg >= FVC_STR && oparg <= FVC_ASCII); + conv_fn = CONVERSION_FUNCTIONS[oparg]; + result = conv_fn(value); + Py_DECREF(value); + if (result == NULL) goto pop_1_error; + #line 4663 "Python/generated_cases.c.h" + stack_pointer[-1] = result; + DISPATCH(); + } - /* If there's a conversion function, call it and replace - value with that result. Otherwise, just use value, - without conversion. */ - if (conv_fn != NULL) { - result = conv_fn(value); + TARGET(FORMAT_SIMPLE) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 3382 "Python/bytecodes.c" + /* If value is a unicode object, then we know the result + * of format(value) is value itself. */ + if (!PyUnicode_CheckExact(value)) { + res = PyObject_Format(value, NULL); Py_DECREF(value); - if (result == NULL) { - Py_XDECREF(fmt_spec); - if (true) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - } - value = result; + if (res == NULL) goto pop_1_error; } + else { + res = value; + } + #line 4682 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + DISPATCH(); + } - result = PyObject_Format(value, fmt_spec); + TARGET(FORMAT_WITH_SPEC) { + PyObject *fmt_spec = stack_pointer[-1]; + PyObject *value = stack_pointer[-2]; + PyObject *res; + #line 3395 "Python/bytecodes.c" + res = PyObject_Format(value, fmt_spec); Py_DECREF(value); - Py_XDECREF(fmt_spec); - if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4692 "Python/generated_cases.c.h" - STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); - stack_pointer[-1] = result; + Py_DECREF(fmt_spec); + if (res == NULL) goto pop_2_error; + #line 4696 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; DISPATCH(); } TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3408 "Python/bytecodes.c" + #line 3402 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4704 "Python/generated_cases.c.h" + #line 4708 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4712,7 +4716,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3413 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4727,12 +4731,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4731 "Python/generated_cases.c.h" + #line 4735 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3428 "Python/bytecodes.c" + #line 3422 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4736 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4742,16 +4746,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3433 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" assert(oparg >= 2); - #line 4748 "Python/generated_cases.c.h" + #line 4752 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3437 "Python/bytecodes.c" + #line 3431 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4763,26 +4767,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4767 "Python/generated_cases.c.h" + #line 4771 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3451 "Python/bytecodes.c" + #line 3445 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4773 "Python/generated_cases.c.h" + #line 4777 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3455 "Python/bytecodes.c" + #line 3449 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4780 "Python/generated_cases.c.h" + #line 4784 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3460 "Python/bytecodes.c" + #line 3454 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4791,12 +4795,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4795 "Python/generated_cases.c.h" + #line 4799 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3471 "Python/bytecodes.c" + #line 3465 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4805,12 +4809,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4809 "Python/generated_cases.c.h" + #line 4813 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3482 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4822,12 +4826,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4826 "Python/generated_cases.c.h" + #line 4830 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3496 "Python/bytecodes.c" + #line 3490 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4839,30 +4843,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4843 "Python/generated_cases.c.h" + #line 4847 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3510 "Python/bytecodes.c" + #line 3504 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4854 "Python/generated_cases.c.h" + #line 4858 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3518 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4861 "Python/generated_cases.c.h" + #line 4865 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3523 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4868 "Python/generated_cases.c.h" + #line 4872 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index faa5087adebf92..d1057e34275add 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -402,8 +402,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case BUILD_SLICE: return ((oparg == 3) ? 1 : 0) + 2; - case FORMAT_VALUE: - return (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0) + 1; + case CONVERT_VALUE: + return 1; + case FORMAT_SIMPLE: + return 1; + case FORMAT_WITH_SPEC: + return 2; case COPY: return (oparg-1) + 1; case BINARY_OP: @@ -820,7 +824,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case BUILD_SLICE: return 1; - case FORMAT_VALUE: + case CONVERT_VALUE: + return 1; + case FORMAT_SIMPLE: + return 1; + case FORMAT_WITH_SPEC: return 1; case COPY: return (oparg-1) + 2; @@ -1064,7 +1072,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [RETURN_GENERATOR] = { true, INSTR_FMT_IX, 0 }, [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [FORMAT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [CONVERT_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, 0 }, + [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, 0 }, [COPY] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index e23c0f04da15c8..451d8bbd17fa63 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -39,6 +39,8 @@ static void *opcode_targets[256] = { &&TARGET_CHECK_EG_MATCH, &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_FORMAT_SIMPLE, + &&TARGET_FORMAT_WITH_SPEC, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, @@ -46,8 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_LIST_APPEND, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, - &&TARGET_CALL_NO_KW_STR_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, + &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_OP_FLOAT, - &&TARGET_COMPARE_OP_INT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_COMPARE_OP_FLOAT, + &&TARGET_COMPARE_OP_INT, &&TARGET_COMPARE_OP_STR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, - &&TARGET_FOR_ITER_GEN, - &&TARGET_LOAD_SUPER_ATTR_ATTR, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_SUPER_ATTR_METHOD, + &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_CLASS, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_LOAD_SUPER_ATTR_ATTR, + &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_RETURN_VALUE, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_LOCALS, - &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,7 +131,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, @@ -147,20 +147,20 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_CONVERT_VALUE, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, From 74c2422fa2d7e17969a7554a3bf17f91e4e5a85f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 14 Jun 2023 08:19:24 -0700 Subject: [PATCH 046/446] Update DSL docs for cases generator (#105753) * Clarify things around goto error/ERROR_IF a bit * Remove docs for super-instructions * Add pseudo; fix heading markup --- .../cases_generator/interpreter_definition.md | 104 ++++++++++-------- 1 file changed, 60 insertions(+), 44 deletions(-) diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index 6f902f60c68ee7..c03870ef59eb49 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -67,17 +67,17 @@ parts of instructions, we can reduce the potential for errors considerably. ## Specification -This specification is at an early stage and is likely to change considerably. +This specification is a work in progress. +We update it as the need arises. -Syntax ------- +### Syntax Each op definition has a kind, a name, a stack and instruction stream effect, and a piece of C code describing its semantics:: ``` file: - (definition | family)+ + (definition | family | pseudo)+ definition: "inst" "(" NAME ["," stack_effect] ")" "{" C-code "}" @@ -85,8 +85,6 @@ and a piece of C code describing its semantics:: "op" "(" NAME "," stack_effect ")" "{" C-code "}" | "macro" "(" NAME ")" "=" uop ("+" uop)* ";" - | - "super" "(" NAME ")" "=" NAME ("+" NAME)* ";" stack_effect: "(" [inputs] "--" [outputs] ")" @@ -122,7 +120,10 @@ and a piece of C code describing its semantics:: object "[" C-expression "]" family: - "family" "(" NAME ")" = "{" NAME ("," NAME)+ "}" ";" + "family" "(" NAME ")" = "{" NAME ("," NAME)+ [","] "}" ";" + + pseudo: + "pseudo" "(" NAME ")" = "{" NAME ("," NAME)+ [","] "}" ";" ``` The following definitions may occur: @@ -130,8 +131,6 @@ The following definitions may occur: * `inst`: A normal instruction, as previously defined by `TARGET(NAME)` in `ceval.c`. * `op`: A part instruction from which macros can be constructed. * `macro`: A bytecode instruction constructed from ops and cache effects. -* `super`: A super-instruction, such as `LOAD_FAST__LOAD_FAST`, constructed from - normal or macro instructions. `NAME` can be any ASCII identifier that is a C identifier and not a C or Python keyword. `foo_1` is legal. `$` is not legal, nor is `struct` or `class`. @@ -159,15 +158,21 @@ By convention cache effects (`stream`) must precede the input effects. The name `oparg` is pre-defined as a 32 bit value fetched from the instruction stream. +### Special functions/macros + The C code may include special functions that are understood by the tools as part of the DSL. Those functions include: * `DEOPT_IF(cond, instruction)`. Deoptimize if `cond` is met. -* `ERROR_IF(cond, label)`. Jump to error handler if `cond` is true. +* `ERROR_IF(cond, label)`. Jump to error handler at `label` if `cond` is true. * `DECREF_INPUTS()`. Generate `Py_DECREF()` calls for the input stack effects. +Note that the use of `DECREF_INPUTS()` is optional -- manual calls +to `Py_DECREF()` or other approaches are also acceptable +(e.g. calling an API that "steals" a reference). + Variables can either be defined in the input, output, or in the C code. Variables defined in the input may not be assigned in the C code. If an `ERROR_IF` occurs, all values will be removed from the stack; @@ -187,17 +192,39 @@ These requirements result in the following constraints on the use of intermediate results.) 3. No `DEOPT_IF` may follow an `ERROR_IF` in the same block. -Semantics ---------- +(There is some wiggle room: these rules apply to dynamic code paths, +not to static occurrences in the source code.) + +If code detects an error condition before the first `DECREF` of an input, +two idioms are valid: + +- Use `goto error`. +- Use a block containing the appropriate `DECREF` calls ending in + `ERROR_IF(true, error)`. + +An example of the latter would be: +```cc + res = PyObject_Add(left, right); + if (res == NULL) { + DECREF_INPUTS(); + ERROR_IF(true, error); + } +``` + +### Semantics The underlying execution model is a stack machine. Operations pop values from the stack, and push values to the stack. They also can look at, and consume, values from the instruction stream. -All members of a family must have the same stack and instruction stream effect. +All members of a family +(which represents a specializable instruction and its specializations) +must have the same stack and instruction stream effect. + +The same is true for all members of a pseudo instruction +(which is mapped by the bytecode compiler to one of its members). -Examples --------- +## Examples (Another source of examples can be found in the [tests](test_generator.py).) @@ -237,27 +264,6 @@ This would generate: } ``` -### Super-instruction definition - -```C - super ( LOAD_FAST__LOAD_FAST ) = LOAD_FAST + LOAD_FAST ; -``` -This might get translated into the following: -```C - TARGET(LOAD_FAST__LOAD_FAST) { - PyObject *value; - value = frame->f_localsplus[oparg]; - Py_INCREF(value); - PUSH(value); - NEXTOPARG(); - next_instr++; - value = frame->f_localsplus[oparg]; - Py_INCREF(value); - PUSH(value); - DISPATCH(); - } -``` - ### Input stack effect and cache effect ```C op ( CHECK_OBJECT_TYPE, (owner, type_version/2 -- owner) ) { @@ -339,14 +345,26 @@ For explanations see "Generating the interpreter" below.) } ``` -### Define an instruction family -These opcodes all share the same instruction format): +### Defining an instruction family + +A _family_ represents a specializable instruction and its specializations. + +Example: These opcodes all share the same instruction format): +```C + family(load_attr) = { LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_SLOT }; +``` + +### Defining a pseudo instruction + +A _pseudo instruction_ is used by the bytecode compiler to represent a set of possible concrete instructions. + +Example: `JUMP` may expand to `JUMP_FORWARD` or `JUMP_BACKWARD`: ```C - family(load_attr) = { LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_SLOT } ; + pseudo(JUMP) = { JUMP_FORWARD, JUMP_BACKWARD }; ``` -Generating the interpreter -========================== + +## Generating the interpreter The generated C code for a single instruction includes a preamble and dispatch at the end which can be easily inserted. What is more complex is ensuring the correct stack effects @@ -401,9 +419,7 @@ rather than popping and pushing, such that `LOAD_ATTR_SLOT` would look something } ``` -Other tools -=========== +## Other tools From the instruction definitions we can generate the stack marking code used in `frame.set_lineno()`, and the tables for use by disassemblers. - From d50930a6a846280b5da299f9c2f9a01669dbf06c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 14 Jun 2023 10:06:50 -0700 Subject: [PATCH 047/446] gh-105481: Fix types and a bug for pseudos (#105788) --- Tools/cases_generator/generate_cases.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 8aa500e9e7412a..8d5739f307abf2 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -510,7 +510,7 @@ class OverriddenInstructionPlaceHolder: name: str -AnyInstruction = Instruction | MacroInstruction +AnyInstruction = Instruction | MacroInstruction | PseudoInstruction INSTR_FMT_PREFIX = "INSTR_FMT_" INSTR_FLAG_SUFFIX = "_FLAG" @@ -550,6 +550,7 @@ def error(self, msg: str, node: parser.Node) -> None: macros: dict[str, parser.Macro] macro_instrs: dict[str, MacroInstruction] families: dict[str, parser.Family] + pseudos: dict[str, parser.Pseudo] pseudo_instrs: dict[str, PseudoInstruction] def parse(self) -> None: @@ -607,7 +608,7 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: # Parse from start psr.setpos(start) - thing: parser.InstDef | parser.Macro | parser.Family | None + thing: parser.InstDef | parser.Macro | parser.Pseudo | parser.Family | None thing_first_token = psr.peek() while thing := psr.definition(): if ws := [w for w in RESERVED_WORDS if variable_used(thing, w)]: @@ -927,7 +928,7 @@ def effect_str(effects: list[StackEffect]) -> str: popped = str(-low) pushed = str(sp - low) case parser.Pseudo(): - instr = self.pseudos[thing.name] + instr = self.pseudo_instrs[thing.name] popped = pushed = None # Calculate stack effect, and check that it's the the same # for all targets. From 820febc535cd9548b11c01c3c6d572b442f20c35 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 21:26:34 +0200 Subject: [PATCH 048/446] gh-75905: Remove test_xmlrpc_net: skipped since 2017 (#105796) test_xmlrpc_net was skipped since 2017: commit 73ffd3f2036179ed54591ef0455e5ba5694ae5bd. The public buildbot.python.org server has no XML-RPC interface anymore, and no replacement server was found in 6 years. --- Lib/test/test_xmlrpc_net.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 Lib/test/test_xmlrpc_net.py diff --git a/Lib/test/test_xmlrpc_net.py b/Lib/test/test_xmlrpc_net.py deleted file mode 100644 index 51167b28bc5a1e..00000000000000 --- a/Lib/test/test_xmlrpc_net.py +++ /dev/null @@ -1,31 +0,0 @@ -import collections.abc -import unittest -from test import support - -import xmlrpc.client as xmlrpclib - - -support.requires("network") - - -@unittest.skip('XXX: buildbot.python.org/all/xmlrpc/ is gone') -class PythonBuildersTest(unittest.TestCase): - - def test_python_builders(self): - # Get the list of builders from the XMLRPC buildbot interface at - # python.org. - server = xmlrpclib.ServerProxy("http://buildbot.python.org/all/xmlrpc/") - try: - builders = server.getAllBuilders() - except OSError as e: - self.skipTest("network error: %s" % e) - self.addCleanup(lambda: server('close')()) - - # Perform a minimal sanity check on the result, just to be sure - # the request means what we think it means. - self.assertIsInstance(builders, collections.abc.Sequence) - self.assertTrue([x for x in builders if "3.x" in x], builders) - - -if __name__ == "__main__": - unittest.main() From 4caa728b2c78c5ded7c91579f21fbb67e3867d80 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 14 Jun 2023 13:50:48 -0700 Subject: [PATCH 049/446] gh-104909: Implement conditional stack effects for macros (#105748) --- Tools/cases_generator/generate_cases.py | 53 +++++++++++++++++++------ Tools/cases_generator/test_generator.py | 40 +++++++++++++++++++ 2 files changed, 80 insertions(+), 13 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 8d5739f307abf2..544568e0294e55 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -179,14 +179,12 @@ def block(self, head: str): def stack_adjust( self, - diff: int, input_effects: list[StackEffect], output_effects: list[StackEffect], ): - # TODO: Get rid of 'diff' parameter shrink, isym = list_effect_size(input_effects) grow, osym = list_effect_size(output_effects) - diff += grow - shrink + diff = grow - shrink if isym and isym != osym: self.emit(f"STACK_SHRINK({isym});") if diff < 0: @@ -355,7 +353,6 @@ def write(self, out: Formatter) -> None: # Write net stack growth/shrinkage out.stack_adjust( - 0, [ieff for ieff in self.input_effects], [oeff for oeff in self.output_effects], ) @@ -848,9 +845,14 @@ def stack_analysis( Ignore cache effects. - Return the list of variable names and the initial stack pointer. + Return the list of variables (as StackEffects) and the initial stack pointer. """ lowest = current = highest = 0 + conditions: dict[int, str] = {} # Indexed by 'current'. + last_instr: Instruction | None = None + for thing in components: + if isinstance(thing, Instruction): + last_instr = thing for thing in components: match thing: case Instruction() as instr: @@ -863,9 +865,24 @@ def stack_analysis( "which are not supported in macro instructions", instr.inst, # TODO: Pass name+location of macro ) + if any(eff.cond for eff in instr.input_effects): + self.error( + f"Instruction {instr.name!r} has conditional input stack effect, " + "which are not supported in macro instructions", + instr.inst, # TODO: Pass name+location of macro + ) + if any(eff.cond for eff in instr.output_effects) and instr is not last_instr: + self.error( + f"Instruction {instr.name!r} has conditional output stack effect, " + "but is not the last instruction in a macro", + instr.inst, # TODO: Pass name+location of macro + ) current -= len(instr.input_effects) lowest = min(lowest, current) - current += len(instr.output_effects) + for eff in instr.output_effects: + if eff.cond: + conditions[current] = eff.cond + current += 1 highest = max(highest, current) case parser.CacheEffect(): pass @@ -874,9 +891,9 @@ def stack_analysis( # At this point, 'current' is the net stack effect, # and 'lowest' and 'highest' are the extremes. # Note that 'lowest' may be negative. - # TODO: Reverse the numbering. stack = [ - StackEffect(f"_tmp_{i+1}", "") for i in reversed(range(highest - lowest)) + StackEffect(f"_tmp_{i}", "", conditions.get(highest - i, "")) + for i in reversed(range(1, highest - lowest + 1)) ] return stack, -lowest @@ -908,6 +925,7 @@ def effect_str(effects: list[StackEffect]) -> str: low = 0 sp = 0 high = 0 + pushed_symbolic: list[str] = [] for comp in parts: for effect in comp.instr.input_effects: assert not effect.cond, effect @@ -915,8 +933,9 @@ def effect_str(effects: list[StackEffect]) -> str: sp -= 1 low = min(low, sp) for effect in comp.instr.output_effects: - assert not effect.cond, effect assert not effect.size, effect + if effect.cond: + pushed_symbolic.append(maybe_parenthesize(f"{maybe_parenthesize(effect.cond)} ? 1 : 0")) sp += 1 high = max(sp, high) if high != max(0, sp): @@ -926,7 +945,8 @@ def effect_str(effects: list[StackEffect]) -> str: # calculations to use the micro ops. self.error("Macro has virtual stack growth", thing) popped = str(-low) - pushed = str(sp - low) + pushed_symbolic.append(str(sp - low - len(pushed_symbolic))) + pushed = " + ".join(pushed_symbolic) case parser.Pseudo(): instr = self.pseudo_instrs[thing.name] popped = pushed = None @@ -1203,7 +1223,15 @@ def wrap_macro(self, mac: MacroInstruction): with self.out.block(f"TARGET({mac.name})"): if mac.predicted: self.out.emit(f"PREDICTED({mac.name});") - for i, var in reversed(list(enumerate(mac.stack))): + + # The input effects should have no conditionals. + # Only the output effects do (for now). + ieffects = [ + StackEffect(eff.name, eff.type) if eff.cond else eff + for eff in mac.stack + ] + + for i, var in reversed(list(enumerate(ieffects))): src = None if i < mac.initial_sp: src = StackEffect(f"stack_pointer[-{mac.initial_sp - i}]", "") @@ -1211,8 +1239,7 @@ def wrap_macro(self, mac: MacroInstruction): yield - # TODO: Use slices of mac.stack instead of numeric values - self.out.stack_adjust(mac.final_sp - mac.initial_sp, [], []) + self.out.stack_adjust(ieffects[:mac.initial_sp], mac.stack[:mac.final_sp]) for i, var in enumerate(reversed(mac.stack[: mac.final_sp]), 1): dst = StackEffect(f"stack_pointer[-{i}]", "") diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index f8c79976fb722e..9ff4c971fd21ac 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -432,3 +432,43 @@ def test_cond_effect(): } """ run_cases_test(input, output) + +def test_macro_cond_effect(): + input = """ + op(A, (left, middle, right --)) { + # Body of A + } + op(B, (-- deep, extra if (oparg), res)) { + # Body of B + } + macro(M) = A + B; + """ + output = """ + TARGET(M) { + PyObject *_tmp_1 = stack_pointer[-1]; + PyObject *_tmp_2 = stack_pointer[-2]; + PyObject *_tmp_3 = stack_pointer[-3]; + { + PyObject *right = _tmp_1; + PyObject *middle = _tmp_2; + PyObject *left = _tmp_3; + # Body of A + } + { + PyObject *deep; + PyObject *extra = NULL; + PyObject *res; + # Body of B + _tmp_3 = deep; + if (oparg) { _tmp_2 = extra; } + _tmp_1 = res; + } + STACK_SHRINK(1); + STACK_GROW((oparg ? 1 : 0)); + stack_pointer[-1] = _tmp_1; + if (oparg) { stack_pointer[-2] = _tmp_2; } + stack_pointer[-3] = _tmp_3; + DISPATCH(); + } + """ + run_cases_test(input, output) From e7507bd131fbfbb49a6819a0d5ad5dd1e21b48cd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 22:56:01 +0200 Subject: [PATCH 050/446] gh-105751: test_ctypes: Remove @need_symbol decorator (GH-105798) Remove the @need_symbol('...') decorator of test.test_ctypes since requested symbols are now always always available in ctypes. Use the @unittest.skipUnless() decorator directly for the two types only available on Windows: * ctypes.WINFUNCTYPE * ctypes.oledll --- Lib/test/test_ctypes/__init__.py | 10 ++-------- Lib/test/test_ctypes/test_arrays.py | 2 -- Lib/test/test_ctypes/test_as_parameter.py | 5 +---- Lib/test/test_ctypes/test_bitfields.py | 6 ------ Lib/test/test_ctypes/test_buffers.py | 4 ---- Lib/test/test_ctypes/test_callbacks.py | 11 +++++------ Lib/test/test_ctypes/test_cast.py | 2 -- Lib/test/test_ctypes/test_cfuncs.py | 7 ------- Lib/test/test_ctypes/test_checkretval.py | 4 ++-- Lib/test/test_ctypes/test_functions.py | 7 ------- Lib/test/test_ctypes/test_memfunctions.py | 2 -- Lib/test/test_ctypes/test_parameters.py | 4 ---- Lib/test/test_ctypes/test_prototypes.py | 3 --- Lib/test/test_ctypes/test_slicing.py | 2 -- Lib/test/test_ctypes/test_strings.py | 3 --- Lib/test/test_ctypes/test_structures.py | 2 -- Lib/test/test_ctypes/test_unicode.py | 2 -- 17 files changed, 10 insertions(+), 66 deletions(-) diff --git a/Lib/test/test_ctypes/__init__.py b/Lib/test/test_ctypes/__init__.py index 6e496fa5a5201b..eb9126cbe18081 100644 --- a/Lib/test/test_ctypes/__init__.py +++ b/Lib/test/test_ctypes/__init__.py @@ -1,16 +1,10 @@ import os -import unittest from test import support from test.support import import_helper -# skip tests if _ctypes was not built -ctypes = import_helper.import_module('ctypes') -ctypes_symbols = dir(ctypes) - -def need_symbol(name): - return unittest.skipUnless(name in ctypes_symbols, - '{!r} is required'.format(name)) +# skip tests if the _ctypes extension was not built +import_helper.import_module('ctypes') def load_tests(*args): return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 4f8747d46ae366..7c35a7e2917bf3 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -8,7 +8,6 @@ c_long, c_ulonglong, c_float, c_double, c_longdouble) from test.support import bigmemtest, _2G -from test.test_ctypes import need_symbol formats = "bBhHiIlLqQfd" @@ -130,7 +129,6 @@ def test_from_address(self): self.assertEqual(sz[1:4:2], b"o") self.assertEqual(sz.value, b"foo") - @need_symbol('create_unicode_buffer') def test_from_addressW(self): p = create_unicode_buffer("foo") sz = (c_wchar * 3).from_address(addressof(p)) diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index 1048c5064c3c17..33b7bd3fadeaae 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -6,7 +6,7 @@ c_short, c_int, c_long, c_longlong, c_byte, c_wchar, c_float, c_double, ArgumentError) -from test.test_ctypes import need_symbol + dll = CDLL(_ctypes_test.__file__) @@ -23,7 +23,6 @@ class BasicWrapTestCase(unittest.TestCase): def wrap(self, param): return param - @need_symbol('c_wchar') def test_wchar_parm(self): f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double] @@ -127,9 +126,7 @@ def callback(value): result = f(self.wrap(-10), self.wrap(cb)) self.assertEqual(result, -18) - @need_symbol('c_longlong') def test_longlong_callbacks(self): - f = dll._testfunc_callback_q_qf f.restype = c_longlong diff --git a/Lib/test/test_ctypes/test_bitfields.py b/Lib/test/test_ctypes/test_bitfields.py index e7b06dd767f9ea..9ffa634dbf707b 100644 --- a/Lib/test/test_ctypes/test_bitfields.py +++ b/Lib/test/test_ctypes/test_bitfields.py @@ -3,7 +3,6 @@ c_byte, c_ubyte, c_char, c_char_p, c_void_p, c_wchar, c_uint32, c_uint64, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong) -from test.test_ctypes import need_symbol from test import support import unittest import os @@ -144,7 +143,6 @@ class Dummy(Structure): result = self.fail_fields(("a", Dummy, 1)) self.assertEqual(result, (TypeError, 'bit fields not allowed for type Dummy')) - @need_symbol('c_wchar') def test_c_wchar(self): result = self.fail_fields(("a", c_wchar, 1)) self.assertEqual(result, @@ -249,7 +247,6 @@ class Y(Structure): _anonymous_ = ["_"] _fields_ = [("_", X)] - @need_symbol('c_uint32') def test_uint32(self): class X(Structure): _fields_ = [("a", c_uint32, 32)] @@ -259,7 +256,6 @@ class X(Structure): x.a = 0xFDCBA987 self.assertEqual(x.a, 0xFDCBA987) - @need_symbol('c_uint64') def test_uint64(self): class X(Structure): _fields_ = [("a", c_uint64, 64)] @@ -269,7 +265,6 @@ class X(Structure): x.a = 0xFEDCBA9876543211 self.assertEqual(x.a, 0xFEDCBA9876543211) - @need_symbol('c_uint32') def test_uint32_swap_little_endian(self): # Issue #23319 class Little(LittleEndianStructure): @@ -283,7 +278,6 @@ class Little(LittleEndianStructure): x.c = 2 self.assertEqual(b, b'\xef\xcd\xab\x21') - @need_symbol('c_uint32') def test_uint32_swap_big_endian(self): # Issue #23319 class Big(BigEndianStructure): diff --git a/Lib/test/test_ctypes/test_buffers.py b/Lib/test/test_ctypes/test_buffers.py index c6c59b926798e0..e446f9e85f9223 100644 --- a/Lib/test/test_ctypes/test_buffers.py +++ b/Lib/test/test_ctypes/test_buffers.py @@ -1,6 +1,5 @@ from ctypes import (create_string_buffer, create_unicode_buffer, sizeof, c_char, c_wchar) -from test.test_ctypes import need_symbol import unittest class StringBufferTestCase(unittest.TestCase): @@ -28,7 +27,6 @@ def test_buffer_interface(self): self.assertEqual(len(bytearray(create_string_buffer(0))), 0) self.assertEqual(len(bytearray(create_string_buffer(1))), 1) - @need_symbol('c_wchar') def test_unicode_buffer(self): b = create_unicode_buffer(32) self.assertEqual(len(b), 32) @@ -48,7 +46,6 @@ def test_unicode_buffer(self): self.assertRaises(TypeError, create_unicode_buffer, b"abc") - @need_symbol('c_wchar') def test_unicode_conversion(self): b = create_unicode_buffer("abc") self.assertEqual(len(b), 4) # trailing nul char @@ -61,7 +58,6 @@ def test_unicode_conversion(self): self.assertEqual(b[::2], "ac") self.assertEqual(b[::5], "a") - @need_symbol('c_wchar') def test_create_unicode_buffer_non_bmp(self): expected = 5 if sizeof(c_wchar) == 2 else 3 for s in '\U00010000\U00100000', '\U00010000\U0010ffff': diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 7ce9775978fa4b..45829b551be8ba 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -9,10 +9,10 @@ c_short, c_ushort, c_int, c_uint, c_long, c_longlong, c_ulonglong, c_ulong, c_float, c_double, c_longdouble, py_object) -from test.test_ctypes import need_symbol from _ctypes import CTYPES_MAX_ARGCOUNT import _ctypes_test + class Callbacks(unittest.TestCase): functype = CFUNCTYPE @@ -71,12 +71,10 @@ def test_long(self): def test_ulong(self): self.check_type(c_ulong, 42) - @need_symbol('c_longlong') def test_longlong(self): self.check_type(c_longlong, 42) self.check_type(c_longlong, -42) - @need_symbol('c_ulonglong') def test_ulonglong(self): self.check_type(c_ulonglong, 42) @@ -90,7 +88,6 @@ def test_double(self): self.check_type(c_double, 3.14) self.check_type(c_double, -3.14) - @need_symbol('c_longdouble') def test_longdouble(self): self.check_type(c_longdouble, 3.14) self.check_type(c_longdouble, -3.14) @@ -156,7 +153,8 @@ def __del__(self): gc.collect() CFUNCTYPE(None)(lambda x=Nasty(): None) - @need_symbol('WINFUNCTYPE') + @unittest.skipUnless(hasattr(ctypes, 'WINFUNCTYPE'), + 'ctypes.WINFUNCTYPE is required') def test_i38748_stackCorruption(self): callback_funcType = ctypes.WINFUNCTYPE(c_long, c_long, c_longlong) @callback_funcType @@ -214,7 +212,8 @@ def cmp_func(a, b): libc.qsort(array, len(array), sizeof(c_int), cmp_func) self.assertEqual(array[:], [1, 5, 7, 33, 99]) - @need_symbol('WINFUNCTYPE') + @unittest.skipUnless(hasattr(ctypes, 'WINFUNCTYPE'), + 'ctypes.WINFUNCTYPE is required') def test_issue_8959_b(self): from ctypes.wintypes import BOOL, HWND, LPARAM global windowCount diff --git a/Lib/test/test_ctypes/test_cast.py b/Lib/test/test_ctypes/test_cast.py index 641b0783515c65..abff120d8b0e36 100644 --- a/Lib/test/test_ctypes/test_cast.py +++ b/Lib/test/test_ctypes/test_cast.py @@ -3,7 +3,6 @@ from ctypes import (Structure, Union, POINTER, cast, sizeof, addressof, c_void_p, c_char_p, c_wchar_p, c_byte, c_short, c_int) -from test.test_ctypes import need_symbol class Test(unittest.TestCase): @@ -78,7 +77,6 @@ def test_char_p(self): self.assertEqual(cast(cast(s, c_void_p), c_char_p).value, b"hiho") - @need_symbol('c_wchar_p') def test_wchar_p(self): s = c_wchar_p("hiho") self.assertEqual(cast(cast(s, c_void_p), c_wchar_p).value, diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py index 9cbde8a13091f2..6969aed8189139 100644 --- a/Lib/test/test_ctypes/test_cfuncs.py +++ b/Lib/test/test_ctypes/test_cfuncs.py @@ -5,7 +5,6 @@ c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble) -from test.test_ctypes import need_symbol import _ctypes_test @@ -113,28 +112,24 @@ def test_ulong_plus(self): self.assertEqual(self._dll.tf_bL(b' ', 4294967295), 1431655765) self.assertEqual(self.U(), 4294967295) - @need_symbol('c_longlong') def test_longlong(self): self._dll.tf_q.restype = c_longlong self._dll.tf_q.argtypes = (c_longlong, ) self.assertEqual(self._dll.tf_q(-9223372036854775806), -3074457345618258602) self.assertEqual(self.S(), -9223372036854775806) - @need_symbol('c_longlong') def test_longlong_plus(self): self._dll.tf_bq.restype = c_longlong self._dll.tf_bq.argtypes = (c_byte, c_longlong) self.assertEqual(self._dll.tf_bq(0, -9223372036854775806), -3074457345618258602) self.assertEqual(self.S(), -9223372036854775806) - @need_symbol('c_ulonglong') def test_ulonglong(self): self._dll.tf_Q.restype = c_ulonglong self._dll.tf_Q.argtypes = (c_ulonglong, ) self.assertEqual(self._dll.tf_Q(18446744073709551615), 6148914691236517205) self.assertEqual(self.U(), 18446744073709551615) - @need_symbol('c_ulonglong') def test_ulonglong_plus(self): self._dll.tf_bQ.restype = c_ulonglong self._dll.tf_bQ.argtypes = (c_byte, c_ulonglong) @@ -165,14 +160,12 @@ def test_double_plus(self): self.assertEqual(self._dll.tf_bd(0, 42.), 14.) self.assertEqual(self.S(), 42) - @need_symbol('c_longdouble') def test_longdouble(self): self._dll.tf_D.restype = c_longdouble self._dll.tf_D.argtypes = (c_longdouble,) self.assertEqual(self._dll.tf_D(42.), 14.) self.assertEqual(self.S(), 42) - @need_symbol('c_longdouble') def test_longdouble_plus(self): self._dll.tf_bD.restype = c_longdouble self._dll.tf_bD.argtypes = (c_byte, c_longdouble) diff --git a/Lib/test/test_ctypes/test_checkretval.py b/Lib/test/test_ctypes/test_checkretval.py index fe5f2442cd7b4e..176102d5a89e76 100644 --- a/Lib/test/test_ctypes/test_checkretval.py +++ b/Lib/test/test_ctypes/test_checkretval.py @@ -1,7 +1,6 @@ import ctypes import unittest from ctypes import CDLL, c_int -from test.test_ctypes import need_symbol class CHECKED(c_int): @@ -28,7 +27,8 @@ def test_checkretval(self): del dll._testfunc_p_p.restype self.assertEqual(42, dll._testfunc_p_p(42)) - @need_symbol('oledll') + @unittest.skipUnless(hasattr(ctypes, 'oledll'), + 'ctypes.oledll is required') def test_oledll(self): oleaut32 = ctypes.oledll.oleaut32 self.assertRaises(OSError, oleaut32.CreateTypeLib2, 0, None, None) diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index a14924a9413cec..7979f0e36b301c 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -11,7 +11,6 @@ c_char, c_wchar, c_byte, c_char_p, c_short, c_int, c_long, c_longlong, c_float, c_double, c_longdouble) -from test.test_ctypes import need_symbol import sys, unittest try: @@ -75,8 +74,6 @@ def callback(*args): "argument 1: TypeError: one character bytes, " "bytearray or integer expected") - - @need_symbol('c_wchar') def test_wchar_parm(self): f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double] @@ -96,7 +93,6 @@ def test_wchar_parm(self): "argument 2: TypeError: one character unicode string " "expected") - @need_symbol('c_wchar') def test_wchar_result(self): f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] @@ -162,7 +158,6 @@ def test_doubleresult(self): self.assertEqual(result, -21) self.assertEqual(type(result), float) - @need_symbol('c_longdouble') def test_longdoubleresult(self): f = dll._testfunc_D_bhilfD f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble] @@ -175,7 +170,6 @@ def test_longdoubleresult(self): self.assertEqual(result, -21) self.assertEqual(type(result), float) - @need_symbol('c_longlong') def test_longlongresult(self): f = dll._testfunc_q_bhilfd f.restype = c_longlong @@ -304,7 +298,6 @@ def callback(value): result = f(-10, cb) self.assertEqual(result, -18) - @need_symbol('c_longlong') def test_longlong_callbacks(self): f = dll._testfunc_callback_q_qf diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py index 3f3b6319edb13a..9d8e156ad5e00e 100644 --- a/Lib/test/test_ctypes/test_memfunctions.py +++ b/Lib/test/test_ctypes/test_memfunctions.py @@ -6,7 +6,6 @@ create_unicode_buffer, wstring_at, memmove, memset, c_char_p, c_byte, c_ubyte, c_wchar) -from test.test_ctypes import need_symbol class MemFunctionsTest(unittest.TestCase): @unittest.skip('test disabled') @@ -67,7 +66,6 @@ def test_string_at(self): self.assertEqual(string_at(b"foo bar", 7), b"foo bar") self.assertEqual(string_at(b"foo bar", 3), b"foo") - @need_symbol('create_unicode_buffer') def test_wstring_at(self): p = create_unicode_buffer("Hello, World") a = create_unicode_buffer(1000000) diff --git a/Lib/test/test_ctypes/test_parameters.py b/Lib/test/test_ctypes/test_parameters.py index 06cc95107b79fa..02a2bc3839a6bb 100644 --- a/Lib/test/test_ctypes/test_parameters.py +++ b/Lib/test/test_ctypes/test_parameters.py @@ -1,5 +1,4 @@ import unittest -from test.test_ctypes import need_symbol import test.support class SimpleTypesTestCase(unittest.TestCase): @@ -36,7 +35,6 @@ def from_param(cls, value): self.assertEqual(CVOIDP.from_param("abc"), "abcabc") self.assertEqual(CCHARP.from_param("abc"), "abcabcabcabc") - @need_symbol('c_wchar_p') def test_subclasses_c_wchar_p(self): from ctypes import c_wchar_p @@ -66,7 +64,6 @@ def test_cstrings(self): a = c_char_p(b"123") self.assertIs(c_char_p.from_param(a), a) - @need_symbol('c_wchar_p') def test_cw_strings(self): from ctypes import c_wchar_p @@ -86,7 +83,6 @@ def test_c_char(self): self.assertEqual(str(cm.exception), "one character bytes, bytearray or integer expected") - @need_symbol('c_wchar') def test_c_wchar(self): from ctypes import c_wchar diff --git a/Lib/test/test_ctypes/test_prototypes.py b/Lib/test/test_ctypes/test_prototypes.py index fe620439a25b29..8dff6d669e937d 100644 --- a/Lib/test/test_ctypes/test_prototypes.py +++ b/Lib/test/test_ctypes/test_prototypes.py @@ -2,7 +2,6 @@ pointer, byref, sizeof, addressof, c_void_p, c_char_p, c_wchar_p, c_char, c_wchar, c_buffer, c_short, c_int, c_long, c_longlong, c_double) -from test.test_ctypes import need_symbol import unittest # IMPORTANT INFO: @@ -142,7 +141,6 @@ def test_c_void_p_arg(self): func(pointer(c_int())) func((c_int * 3)()) - @need_symbol('c_wchar_p') def test_c_void_p_arg_with_c_wchar_p(self): func = testdll._testfunc_p_p func.restype = c_wchar_p @@ -164,7 +162,6 @@ class X: func.argtypes = None self.assertEqual(None, func(X())) -@need_symbol('c_wchar') class WCharPointersTestCase(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_ctypes/test_slicing.py b/Lib/test/test_ctypes/test_slicing.py index 8979b27fda2141..91385e995c9059 100644 --- a/Lib/test/test_ctypes/test_slicing.py +++ b/Lib/test/test_ctypes/test_slicing.py @@ -1,7 +1,6 @@ import unittest from ctypes import (CDLL, POINTER, sizeof, c_byte, c_short, c_int, c_long, c_char, c_wchar, c_char_p) -from test.test_ctypes import need_symbol import _ctypes_test @@ -127,7 +126,6 @@ def test_char_array(self): self.assertEqual(p[2:5:-3], s[2:5:-3]) - @need_symbol('c_wchar') def test_wchar_ptr(self): s = "abcdefghijklmnopqrstuvwxyz\0" diff --git a/Lib/test/test_ctypes/test_strings.py b/Lib/test/test_ctypes/test_strings.py index 62d84cc43aa9b2..f02d6077def1d8 100644 --- a/Lib/test/test_ctypes/test_strings.py +++ b/Lib/test/test_ctypes/test_strings.py @@ -1,6 +1,5 @@ import unittest from ctypes import c_buffer, sizeof, byref, c_char, c_wchar -from test.test_ctypes import need_symbol class StringArrayTestCase(unittest.TestCase): def test(self): @@ -61,7 +60,6 @@ def test_del_segfault(self): del buf.raw -@need_symbol('c_wchar') class WStringArrayTestCase(unittest.TestCase): def test(self): BUF = c_wchar * 4 @@ -86,7 +84,6 @@ def test_nonbmp(self): self.assertEqual(w.value, u) -@need_symbol('c_wchar') class WStringTestCase(unittest.TestCase): def test_wchar(self): c_wchar("x") diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 04ed73a49c76fd..98099e8b8c087c 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -6,7 +6,6 @@ c_uint8, c_uint16, c_uint32, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) -from test.test_ctypes import need_symbol from struct import calcsize import _ctypes_test from test import support @@ -307,7 +306,6 @@ class Person(Structure): self.assertEqual(p.phone.number, b"5678") self.assertEqual(p.age, 5) - @need_symbol('c_wchar') def test_structures_with_wchar(self): class PersonW(Structure): _fields_ = [("name", c_wchar * 12), diff --git a/Lib/test/test_ctypes/test_unicode.py b/Lib/test/test_ctypes/test_unicode.py index 319cb3b1dcac21..fe8a157f3c60a7 100644 --- a/Lib/test/test_ctypes/test_unicode.py +++ b/Lib/test/test_ctypes/test_unicode.py @@ -1,10 +1,8 @@ import unittest import ctypes -from test.test_ctypes import need_symbol import _ctypes_test -@need_symbol('c_wchar') class UnicodeTestCase(unittest.TestCase): def test_wcslen(self): dll = ctypes.CDLL(_ctypes_test.__file__) From 5ab13c5f97aa5226c49052f1ad19a8c97a3d7cdf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 14 Jun 2023 23:29:05 +0200 Subject: [PATCH 051/446] gh-105751: test_ctypes avoids the operator module (GH-105797) * Replace operator.delitem(obj, index) with "del obj[index]". * Replace operator.setitem(obj, index, value) with "obj[index] = value". * Replace delattr(obj, "attr) with "del obj.attr". * Replace grc() with sys.getrefcount() for readability. --- Lib/test/test_ctypes/test_arrays.py | 8 ++-- Lib/test/test_ctypes/test_callbacks.py | 8 ++-- Lib/test/test_ctypes/test_delattr.py | 14 ++++--- Lib/test/test_ctypes/test_internals.py | 10 ++--- Lib/test/test_ctypes/test_keeprefs.py | 11 +++--- Lib/test/test_ctypes/test_pointers.py | 4 +- Lib/test/test_ctypes/test_python_api.py | 22 +++++------ Lib/test/test_ctypes/test_refcounts.py | 32 ++++++++-------- Lib/test/test_ctypes/test_slicing.py | 50 +++++++++++++------------ Lib/test/test_ctypes/test_stringptr.py | 6 +-- 10 files changed, 85 insertions(+), 80 deletions(-) diff --git a/Lib/test/test_ctypes/test_arrays.py b/Lib/test/test_ctypes/test_arrays.py index 7c35a7e2917bf3..f7a4b5df514e5b 100644 --- a/Lib/test/test_ctypes/test_arrays.py +++ b/Lib/test/test_ctypes/test_arrays.py @@ -46,9 +46,9 @@ def test_simple(self): with self.assertRaises(IndexError): ia[-alen-1] # change the items - from operator import setitem new_values = list(range(42, 42+alen)) - [setitem(ia, n, new_values[n]) for n in range(alen)] + for n in range(alen): + ia[n] = new_values[n] values = [ia[i] for i in range(alen)] self.assertEqual(values, new_values) @@ -78,8 +78,8 @@ def test_simple(self): self.assertEqual(len(ca), 3) # cannot delete items - from operator import delitem - self.assertRaises(TypeError, delitem, ca, 0) + with self.assertRaises(TypeError): + del ca[0] def test_step_overflow(self): a = (c_int * 5)() diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 45829b551be8ba..50c2650cb345ab 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -1,4 +1,5 @@ import functools +import sys import unittest from test import support @@ -106,15 +107,14 @@ def test_char_p(self): def test_pyobject(self): o = () - from sys import getrefcount as grc for o in (), [], object(): - initial = grc(o) + initial = sys.getrefcount(o) # This call leaks a reference to 'o'... self.check_type(py_object, o) - before = grc(o) + before = sys.getrefcount(o) # ...but this call doesn't leak any more. Where is the refcount? self.check_type(py_object, o) - after = grc(o) + after = sys.getrefcount(o) self.assertEqual((after, o), (before, o)) def test_unsupported_restype_1(self): diff --git a/Lib/test/test_ctypes/test_delattr.py b/Lib/test/test_ctypes/test_delattr.py index 10d2fe066fc068..e80b5fa6efb545 100644 --- a/Lib/test/test_ctypes/test_delattr.py +++ b/Lib/test/test_ctypes/test_delattr.py @@ -8,16 +8,18 @@ class X(Structure): class TestCase(unittest.TestCase): def test_simple(self): - self.assertRaises(TypeError, - delattr, c_int(42), "value") + with self.assertRaises(TypeError): + del c_int(42).value def test_chararray(self): - self.assertRaises(TypeError, - delattr, (c_char * 5)(), "value") + chararray = (c_char * 5)() + with self.assertRaises(TypeError): + del chararray.value def test_struct(self): - self.assertRaises(TypeError, - delattr, X(), "foo") + struct = X() + with self.assertRaises(TypeError): + del struct.foo if __name__ == "__main__": diff --git a/Lib/test/test_ctypes/test_internals.py b/Lib/test/test_ctypes/test_internals.py index 1290f80111d283..06826eb9ebd710 100644 --- a/Lib/test/test_ctypes/test_internals.py +++ b/Lib/test/test_ctypes/test_internals.py @@ -1,7 +1,7 @@ # This tests the internal _objects attribute +import sys import unittest from ctypes import Structure, POINTER, c_char_p, c_int -from sys import getrefcount as grc # XXX This test must be reviewed for correctness!!! @@ -20,16 +20,16 @@ def assertSame(self, a, b): def test_ints(self): i = 42000123 - refcnt = grc(i) + refcnt = sys.getrefcount(i) ci = c_int(i) - self.assertEqual(refcnt, grc(i)) + self.assertEqual(refcnt, sys.getrefcount(i)) self.assertEqual(ci._objects, None) def test_c_char_p(self): s = b"Hello, World" - refcnt = grc(s) + refcnt = sys.getrefcount(s) cs = c_char_p(s) - self.assertEqual(refcnt + 1, grc(s)) + self.assertEqual(refcnt + 1, sys.getrefcount(s)) self.assertSame(cs._objects, s) def test_simple_struct(self): diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index ecfcda13945dc6..6fb0628ad3b6eb 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -1,5 +1,7 @@ -from ctypes import Structure, POINTER, pointer, c_char_p, c_int +import sys import unittest +from ctypes import Structure, POINTER, pointer, c_char_p, c_int + class SimpleTestCase(unittest.TestCase): def test_cint(self): @@ -100,16 +102,15 @@ class X(Structure): _fields_ = [("p", POINTER(c_char_p))] x = X() i = c_char_p("abc def") - from sys import getrefcount as grc - print("2?", grc(i)) + print("2?", sys.getrefcount(i)) x.p = pointer(i) - print("3?", grc(i)) + print("3?", sys.getrefcount(i)) for i in range(320): c_int(99) x.p[0] print(x.p[0]) ## del x -## print "2?", grc(i) +## print "2?", sys.getrefcount(i) ## del i import gc gc.collect() diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index 7d13aebdbbeafe..7e25d8276bbb2c 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -97,7 +97,6 @@ def func(arg): ## print self.result def test_basics(self): - from operator import delitem for ct, pt in zip(ctype_types, python_types): i = ct(42) p = pointer(i) @@ -108,7 +107,8 @@ def test_basics(self): ## self.assertEqual(p.contents, 42) ## self.assertEqual(p[0], 42) - self.assertRaises(TypeError, delitem, p, 0) + with self.assertRaises(TypeError): + del p[0] def test_from_address(self): from array import array diff --git a/Lib/test/test_ctypes/test_python_api.py b/Lib/test/test_ctypes/test_python_api.py index 3799311751a055..c8b81196609f93 100644 --- a/Lib/test/test_ctypes/test_python_api.py +++ b/Lib/test/test_ctypes/test_python_api.py @@ -1,4 +1,5 @@ import unittest +import sys from test import support from ctypes import (pythonapi, POINTER, c_buffer, sizeof, py_object, c_char_p, c_char, c_long, c_size_t) @@ -11,7 +12,6 @@ ################################################################ -from sys import getrefcount as grc class PythonAPITestCase(unittest.TestCase): @@ -29,41 +29,41 @@ def test_PyString_FromString(self): pythonapi.PyBytes_FromString.argtypes = (c_char_p,) s = b"abc" - refcnt = grc(s) + refcnt = sys.getrefcount(s) pyob = pythonapi.PyBytes_FromString(s) - self.assertEqual(grc(s), refcnt) + self.assertEqual(sys.getrefcount(s), refcnt) self.assertEqual(s, pyob) del pyob - self.assertEqual(grc(s), refcnt) + self.assertEqual(sys.getrefcount(s), refcnt) @support.refcount_test def test_PyLong_Long(self): - ref42 = grc(42) + ref42 = sys.getrefcount(42) pythonapi.PyLong_FromLong.restype = py_object self.assertEqual(pythonapi.PyLong_FromLong(42), 42) - self.assertEqual(grc(42), ref42) + self.assertEqual(sys.getrefcount(42), ref42) pythonapi.PyLong_AsLong.argtypes = (py_object,) pythonapi.PyLong_AsLong.restype = c_long res = pythonapi.PyLong_AsLong(42) # Small int refcnts don't change - self.assertEqual(grc(res), ref42) + self.assertEqual(sys.getrefcount(res), ref42) del res - self.assertEqual(grc(42), ref42) + self.assertEqual(sys.getrefcount(42), ref42) @support.refcount_test def test_PyObj_FromPtr(self): s = "abc def ghi jkl" - ref = grc(s) + ref = sys.getrefcount(s) # id(python-object) is the address pyobj = PyObj_FromPtr(id(s)) self.assertIs(s, pyobj) - self.assertEqual(grc(s), ref + 1) + self.assertEqual(sys.getrefcount(s), ref + 1) del pyobj - self.assertEqual(grc(s), ref) + self.assertEqual(sys.getrefcount(s), ref) def test_PyOS_snprintf(self): PyOS_snprintf = pythonapi.PyOS_snprintf diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index 48958cd2a60196..b05cad0512c18e 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -1,7 +1,8 @@ -import unittest -from test import support import ctypes import gc +import sys +import unittest +from test import support MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int) OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) @@ -13,8 +14,6 @@ class RefcountTestCase(unittest.TestCase): @support.refcount_test def test_1(self): - from sys import getrefcount as grc - f = dll._testfunc_callback_i_if f.restype = ctypes.c_int f.argtypes = [ctypes.c_int, MyCallback] @@ -23,38 +22,37 @@ def callback(value): #print "called back with", value return value - self.assertEqual(grc(callback), 2) + self.assertEqual(sys.getrefcount(callback), 2) cb = MyCallback(callback) - self.assertGreater(grc(callback), 2) + self.assertGreater(sys.getrefcount(callback), 2) result = f(-10, cb) self.assertEqual(result, -18) cb = None gc.collect() - self.assertEqual(grc(callback), 2) + self.assertEqual(sys.getrefcount(callback), 2) @support.refcount_test def test_refcount(self): - from sys import getrefcount as grc def func(*args): pass # this is the standard refcount for func - self.assertEqual(grc(func), 2) + self.assertEqual(sys.getrefcount(func), 2) # the CFuncPtr instance holds at least one refcount on func: f = OtherCallback(func) - self.assertGreater(grc(func), 2) + self.assertGreater(sys.getrefcount(func), 2) # and may release it again del f - self.assertGreaterEqual(grc(func), 2) + self.assertGreaterEqual(sys.getrefcount(func), 2) # but now it must be gone gc.collect() - self.assertEqual(grc(func), 2) + self.assertEqual(sys.getrefcount(func), 2) class X(ctypes.Structure): _fields_ = [("a", OtherCallback)] @@ -62,27 +60,27 @@ class X(ctypes.Structure): x.a = OtherCallback(func) # the CFuncPtr instance holds at least one refcount on func: - self.assertGreater(grc(func), 2) + self.assertGreater(sys.getrefcount(func), 2) # and may release it again del x - self.assertGreaterEqual(grc(func), 2) + self.assertGreaterEqual(sys.getrefcount(func), 2) # and now it must be gone again gc.collect() - self.assertEqual(grc(func), 2) + self.assertEqual(sys.getrefcount(func), 2) f = OtherCallback(func) # the CFuncPtr instance holds at least one refcount on func: - self.assertGreater(grc(func), 2) + self.assertGreater(sys.getrefcount(func), 2) # create a cycle f.cycle = f del f gc.collect() - self.assertEqual(grc(func), 2) + self.assertEqual(sys.getrefcount(func), 2) class AnotherLeak(unittest.TestCase): def test_callback(self): diff --git a/Lib/test/test_ctypes/test_slicing.py b/Lib/test/test_ctypes/test_slicing.py index 91385e995c9059..30db90cd7c0f5e 100644 --- a/Lib/test/test_ctypes/test_slicing.py +++ b/Lib/test/test_ctypes/test_slicing.py @@ -46,18 +46,21 @@ def test_setslice_cint(self): b[33::-3] = range(12) self.assertEqual(a[:], b) - from operator import setitem - # TypeError: int expected instead of str instance - self.assertRaises(TypeError, setitem, a, slice(0, 5), "abcde") + with self.assertRaises(TypeError): + a[:5] = "abcde" + # TypeError: int expected instead of str instance - self.assertRaises(TypeError, setitem, a, slice(0, 5), - ["a", "b", "c", "d", "e"]) + with self.assertRaises(TypeError): + a[:5] = ["a", "b", "c", "d", "e"] + # TypeError: int expected instead of float instance - self.assertRaises(TypeError, setitem, a, slice(0, 5), - [1, 2, 3, 4, 3.14]) + with self.assertRaises(TypeError): + a[:5] = [1, 2, 3, 4, 3.14] + # ValueError: Can only assign sequence of same size - self.assertRaises(ValueError, setitem, a, slice(0, 5), range(32)) + with self.assertRaises(ValueError): + a[:5] = range(32) def test_char_ptr(self): s = b"abcdefghijklmnopqrstuvwxyz" @@ -73,18 +76,20 @@ def test_char_ptr(self): self.assertEqual(res[len(s)-1:5:-7], s[:5:-7]) self.assertEqual(res[0:-1:-1], s[0::-1]) - import operator - self.assertRaises(ValueError, operator.getitem, - res, slice(None, None, None)) - self.assertRaises(ValueError, operator.getitem, - res, slice(0, None, None)) - self.assertRaises(ValueError, operator.getitem, - res, slice(None, 5, -1)) - self.assertRaises(ValueError, operator.getitem, - res, slice(-5, None, None)) - - self.assertRaises(TypeError, operator.setitem, - res, slice(0, 5), "abcde") + # get items + with self.assertRaises(ValueError): + res[:] + with self.assertRaises(ValueError): + res[0:] + with self.assertRaises(ValueError): + res[:5:-1] + with self.assertRaises(ValueError): + res[-5:] + + # set items + with self.assertRaises(TypeError): + res[:5] = "abcde" + dll.my_free(res) dll.my_strdup.restype = POINTER(c_byte) @@ -139,9 +144,8 @@ def test_wchar_ptr(self): self.assertEqual(res[len(s)-1:-1:-1], s[::-1]) self.assertEqual(res[len(s)-1:5:-7], s[:5:-7]) - import operator - self.assertRaises(TypeError, operator.setitem, - res, slice(0, 5), "abcde") + with self.assertRaises(TypeError): + res[:5] = "abcde" dll.my_free(res) if sizeof(c_wchar) == sizeof(c_short): diff --git a/Lib/test/test_ctypes/test_stringptr.py b/Lib/test/test_ctypes/test_stringptr.py index 1eae154a907b5e..8bf04339d44b39 100644 --- a/Lib/test/test_ctypes/test_stringptr.py +++ b/Lib/test/test_ctypes/test_stringptr.py @@ -1,4 +1,5 @@ import unittest +import sys from test import support from ctypes import CDLL, Structure, POINTER, c_buffer, c_char, c_char_p @@ -17,10 +18,9 @@ class X(Structure): # NULL pointer access self.assertRaises(ValueError, getattr, x.str, "contents") b = c_buffer(b"Hello, World") - from sys import getrefcount as grc - self.assertEqual(grc(b), 2) + self.assertEqual(sys.getrefcount(b), 2) x.str = b - self.assertEqual(grc(b), 3) + self.assertEqual(sys.getrefcount(b), 3) # POINTER(c_char) and Python string is NOT compatible # POINTER(c_char) and c_buffer() is compatible From d1b0297d3e1cb4f9f53070e6c0a5fd6722bdf6ee Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 15 Jun 2023 00:14:22 +0100 Subject: [PATCH 052/446] gh-105481: add HAS_JUMP flag to opcode metadata (#105791) --- Include/internal/pycore_opcode_utils.h | 4 +- Python/bytecodes.c | 34 +-- Python/ceval_macros.h | 6 + Python/compile.c | 5 +- Python/flowgraph.c | 3 +- Python/generated_cases.c.h | 272 ++++++++++++------------ Python/opcode_metadata.h | 30 +-- Tools/cases_generator/generate_cases.py | 3 +- 8 files changed, 189 insertions(+), 168 deletions(-) diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h index 5ab31e6588536d..d80b3c1c20b149 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -26,11 +26,11 @@ extern "C" { (opcode) == SETUP_CLEANUP) #define HAS_TARGET(opcode) \ - (IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)) + (OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)) /* opcodes that must be last in the basicblock */ #define IS_TERMINATOR_OPCODE(opcode) \ - (IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) + (OPCODE_HAS_JUMP(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) /* opcodes which are not emitted in codegen stage, only by the assembler */ #define IS_ASSEMBLER_OPCODE(opcode) \ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ddb43ddad1f742..a2cb834df29822 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -430,7 +430,7 @@ dummy_func( _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); ERROR_IF(*target_local == NULL, error); // The STORE_FAST is already done. - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } macro(BINARY_OP_INPLACE_ADD_UNICODE) = @@ -557,7 +557,7 @@ dummy_func( STACK_SHRINK(2); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -879,7 +879,7 @@ dummy_func( gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND); + SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { @@ -918,7 +918,7 @@ dummy_func( gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND); + SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } @@ -1905,7 +1905,7 @@ dummy_func( int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -1933,7 +1933,7 @@ dummy_func( STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -2356,8 +2356,9 @@ dummy_func( next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); } // Common case: no jump, leave it to the code generator @@ -2406,8 +2407,9 @@ dummy_func( } Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator @@ -2428,8 +2430,9 @@ dummy_func( } Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator @@ -2442,8 +2445,9 @@ dummy_func( if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); // Jump over END_FOR instruction. - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); } long value = r->start; @@ -2467,7 +2471,7 @@ dummy_func( gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); @@ -2738,7 +2742,7 @@ dummy_func( if (new_frame == NULL) { goto error; } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -2812,7 +2816,7 @@ dummy_func( } // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -2850,7 +2854,7 @@ dummy_func( } // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -3093,7 +3097,7 @@ dummy_func( Py_DECREF(method); STACK_SHRINK(3); // CALL + POP_TOP - JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); } diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 1130b10ef7638b..706a9a24b26b04 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -145,7 +145,13 @@ GETITEM(PyObject *v, Py_ssize_t i) { oparg = word.op.arg; \ } while (0) #define JUMPTO(x) (next_instr = _PyCode_CODE(_PyFrame_GetCode(frame)) + (x)) + +/* JUMPBY makes the generator identify the instruction as a jump. SKIP_OVER is + * for advancing to the next instruction, taking into account cache entries + * and skipped instructions. + */ #define JUMPBY(x) (next_instr += (x)) +#define SKIP_OVER(x) (next_instr += (x)) /* OpCode prediction macros Some opcodes tend to come in pairs thus making it possible to diff --git a/Python/compile.c b/Python/compile.c index daeb4dbeed987e..afb7b7dd3932eb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -248,8 +248,11 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) { static int instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { + /* compare old and new opcode macros - use ! to compare as bools. */ assert(!HAS_ARG(opcode) == !OPCODE_HAS_ARG(opcode)); assert(!HAS_CONST(opcode) == !OPCODE_HAS_CONST(opcode)); + assert(!OPCODE_HAS_JUMP(opcode) == !OPCODE_HAS_JUMP(opcode)); + assert(0 <= opcode && opcode <= MAX_OPCODE); assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode)); assert(IS_WITHIN_OPCODE_RANGE(opcode)); @@ -1114,7 +1117,7 @@ codegen_addop_j(instr_sequence *seq, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); - assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); + assert(OPCODE_HAS_JUMP(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, target.id, loc); } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 889eba40b14a2e..de5c5e7ecc38d6 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -45,7 +45,8 @@ is_block_push(cfg_instr *i) static inline int is_jump(cfg_instr *i) { - return IS_JUMP_OPCODE(i->i_opcode); + assert(!OPCODE_HAS_JUMP(i->i_opcode) == !IS_JUMP_OPCODE(i->i_opcode)); + return OPCODE_HAS_JUMP(i->i_opcode); } /* One arg*/ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8e3f925a2a655a..13c3e286e2ddbf 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -566,7 +566,7 @@ _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_OP + 1); #line 571 "Python/generated_cases.c.h" } STACK_SHRINK(2); @@ -751,7 +751,7 @@ STACK_SHRINK(2); new_frame->localsplus[0] = container; new_frame->localsplus[1] = sub; - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 758 "Python/generated_cases.c.h" @@ -1183,7 +1183,7 @@ gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND); + SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); } if (Py_IsNone(v) && PyIter_Check(receiver)) { @@ -1229,7 +1229,7 @@ gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_SEND); + SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); #line 1235 "Python/generated_cases.c.h" } @@ -2689,7 +2689,7 @@ int shrink_stack = !(oparg & 1); STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 2696 "Python/generated_cases.c.h" @@ -2723,7 +2723,7 @@ STACK_SHRINK(shrink_stack); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); #line 2730 "Python/generated_cases.c.h" @@ -3350,12 +3350,13 @@ next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3359 "Python/generated_cases.c.h" + #line 3360 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3363,7 +3364,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2367 "Python/bytecodes.c" + #line 2368 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3389,14 +3390,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3393 "Python/generated_cases.c.h" + #line 3394 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2395 "Python/bytecodes.c" + #line 2396 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3411,12 +3412,13 @@ } Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3420 "Python/generated_cases.c.h" + #line 3422 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3426,7 +3428,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2417 "Python/bytecodes.c" + #line 2419 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3441,12 +3443,13 @@ } Py_DECREF(iter); STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3450 "Python/generated_cases.c.h" + #line 3453 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3456,15 +3459,16 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2439 "Python/bytecodes.c" + #line 2442 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); // Jump over END_FOR instruction. - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + JUMPBY(oparg + 1); DISPATCH(); } long value = r->start; @@ -3474,7 +3478,7 @@ if (next == NULL) { goto error; } - #line 3478 "Python/generated_cases.c.h" + #line 3482 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3483,7 +3487,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2459 "Python/bytecodes.c" + #line 2463 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3495,18 +3499,18 @@ gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3503 "Python/generated_cases.c.h" + #line 3507 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2477 "Python/bytecodes.c" + #line 2481 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3529,16 +3533,16 @@ Py_DECREF(enter); goto error; } - #line 3533 "Python/generated_cases.c.h" + #line 3537 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2500 "Python/bytecodes.c" + #line 2504 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3542 "Python/generated_cases.c.h" + #line 3546 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3549,7 +3553,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2509 "Python/bytecodes.c" + #line 2513 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3575,16 +3579,16 @@ Py_DECREF(enter); goto error; } - #line 3579 "Python/generated_cases.c.h" + #line 3583 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2535 "Python/bytecodes.c" + #line 2539 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3588 "Python/generated_cases.c.h" + #line 3592 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3596,7 +3600,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2544 "Python/bytecodes.c" + #line 2548 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3617,7 +3621,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3621 "Python/generated_cases.c.h" + #line 3625 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3626,7 +3630,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2583 "Python/bytecodes.c" + #line 2587 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3636,7 +3640,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3640 "Python/generated_cases.c.h" + #line 3644 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3650,7 +3654,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2595 "Python/bytecodes.c" + #line 2599 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3667,7 +3671,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3671 "Python/generated_cases.c.h" + #line 3675 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3681,7 +3685,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2614 "Python/bytecodes.c" + #line 2618 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3691,7 +3695,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3695 "Python/generated_cases.c.h" + #line 3699 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3705,7 +3709,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2626 "Python/bytecodes.c" + #line 2630 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3719,7 +3723,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3723 "Python/generated_cases.c.h" + #line 3727 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3728,16 +3732,16 @@ } TARGET(KW_NAMES) { - #line 2642 "Python/bytecodes.c" + #line 2646 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3736 "Python/generated_cases.c.h" + #line 3740 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2648 "Python/bytecodes.c" + #line 2652 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3750,7 +3754,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3754 "Python/generated_cases.c.h" + #line 3758 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3760,7 +3764,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2693 "Python/bytecodes.c" + #line 2697 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3809,7 +3813,7 @@ if (new_frame == NULL) { goto error; } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } @@ -3842,7 +3846,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3846 "Python/generated_cases.c.h" + #line 3850 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3854,7 +3858,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2781 "Python/bytecodes.c" + #line 2785 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3864,7 +3868,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3868 "Python/generated_cases.c.h" + #line 3872 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3873,7 +3877,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2793 "Python/bytecodes.c" + #line 2797 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3896,10 +3900,10 @@ } // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3903 "Python/generated_cases.c.h" + #line 3907 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3907,7 +3911,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2821 "Python/bytecodes.c" + #line 2825 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3940,10 +3944,10 @@ } // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3947 "Python/generated_cases.c.h" + #line 3951 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3951,7 +3955,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2859 "Python/bytecodes.c" + #line 2863 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3961,7 +3965,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3965 "Python/generated_cases.c.h" + #line 3969 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3974,7 +3978,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2871 "Python/bytecodes.c" + #line 2875 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3985,7 +3989,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3989 "Python/generated_cases.c.h" + #line 3993 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3999,7 +4003,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2885 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4010,7 +4014,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4014 "Python/generated_cases.c.h" + #line 4018 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4024,7 +4028,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2899 "Python/bytecodes.c" + #line 2903 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4046,7 +4050,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4050 "Python/generated_cases.c.h" + #line 4054 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4060,7 +4064,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2924 "Python/bytecodes.c" + #line 2928 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4088,7 +4092,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4092 "Python/generated_cases.c.h" + #line 4096 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4102,7 +4106,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2955 "Python/bytecodes.c" + #line 2959 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4134,7 +4138,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4138 "Python/generated_cases.c.h" + #line 4142 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4148,7 +4152,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 2994 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4180,7 +4184,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4184 "Python/generated_cases.c.h" + #line 4188 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4194,7 +4198,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3025 "Python/bytecodes.c" + #line 3029 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4219,7 +4223,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4223 "Python/generated_cases.c.h" + #line 4227 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4232,7 +4236,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3052 "Python/bytecodes.c" + #line 3056 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4259,7 +4263,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4263 "Python/generated_cases.c.h" + #line 4267 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4271,7 +4275,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3082 "Python/bytecodes.c" + #line 3086 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4286,17 +4290,17 @@ Py_DECREF(method); STACK_SHRINK(3); // CALL + POP_TOP - JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4293 "Python/generated_cases.c.h" + #line 4297 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3102 "Python/bytecodes.c" + #line 3106 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4327,7 +4331,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4331 "Python/generated_cases.c.h" + #line 4335 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4340,7 +4344,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3136 "Python/bytecodes.c" + #line 3140 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4369,7 +4373,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4373 "Python/generated_cases.c.h" + #line 4377 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4382,7 +4386,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3168 "Python/bytecodes.c" + #line 3172 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4411,7 +4415,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4415 "Python/generated_cases.c.h" + #line 4419 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4424,7 +4428,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3200 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4452,7 +4456,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4456 "Python/generated_cases.c.h" + #line 4460 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4462,9 +4466,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3231 "Python/bytecodes.c" + #line 3235 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4468 "Python/generated_cases.c.h" + #line 4472 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4473,7 +4477,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3235 "Python/bytecodes.c" + #line 3239 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4535,14 +4539,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4539 "Python/generated_cases.c.h" + #line 4543 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3297 "Python/bytecodes.c" + #line 3301 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4546 "Python/generated_cases.c.h" + #line 4550 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4553,7 +4557,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3303 "Python/bytecodes.c" + #line 3307 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4565,7 +4569,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4569 "Python/generated_cases.c.h" + #line 4573 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4573,7 +4577,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3317 "Python/bytecodes.c" + #line 3321 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4598,14 +4602,14 @@ default: Py_UNREACHABLE(); } - #line 4602 "Python/generated_cases.c.h" + #line 4606 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3344 "Python/bytecodes.c" + #line 3348 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4626,7 +4630,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4630 "Python/generated_cases.c.h" + #line 4634 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4634,15 +4638,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3367 "Python/bytecodes.c" + #line 3371 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4640 "Python/generated_cases.c.h" + #line 4644 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3369 "Python/bytecodes.c" + #line 3373 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4646 "Python/generated_cases.c.h" + #line 4650 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4652,14 +4656,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3373 "Python/bytecodes.c" + #line 3377 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4663 "Python/generated_cases.c.h" + #line 4667 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4667,7 +4671,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3382 "Python/bytecodes.c" + #line 3386 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4678,7 +4682,7 @@ else { res = value; } - #line 4682 "Python/generated_cases.c.h" + #line 4686 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4687,12 +4691,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3395 "Python/bytecodes.c" + #line 3399 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4696 "Python/generated_cases.c.h" + #line 4700 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4701,10 +4705,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3402 "Python/bytecodes.c" + #line 3406 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4708 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4716,7 +4720,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3407 "Python/bytecodes.c" + #line 3411 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4731,12 +4735,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4735 "Python/generated_cases.c.h" + #line 4739 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3422 "Python/bytecodes.c" + #line 3426 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4740 "Python/generated_cases.c.h" + #line 4744 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4746,16 +4750,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3427 "Python/bytecodes.c" + #line 3431 "Python/bytecodes.c" assert(oparg >= 2); - #line 4752 "Python/generated_cases.c.h" + #line 4756 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3431 "Python/bytecodes.c" + #line 3435 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4767,26 +4771,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4771 "Python/generated_cases.c.h" + #line 4775 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3445 "Python/bytecodes.c" + #line 3449 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4777 "Python/generated_cases.c.h" + #line 4781 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3449 "Python/bytecodes.c" + #line 3453 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4784 "Python/generated_cases.c.h" + #line 4788 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3454 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4795,12 +4799,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4799 "Python/generated_cases.c.h" + #line 4803 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3465 "Python/bytecodes.c" + #line 3469 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4809,12 +4813,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4813 "Python/generated_cases.c.h" + #line 4817 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3476 "Python/bytecodes.c" + #line 3480 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4826,12 +4830,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4830 "Python/generated_cases.c.h" + #line 4834 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3490 "Python/bytecodes.c" + #line 3494 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4843,30 +4847,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4847 "Python/generated_cases.c.h" + #line 4851 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3504 "Python/bytecodes.c" + #line 3508 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4858 "Python/generated_cases.c.h" + #line 4862 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3512 "Python/bytecodes.c" + #line 3516 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4865 "Python/generated_cases.c.h" + #line 4869 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3517 "Python/bytecodes.c" + #line 3521 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4872 "Python/generated_cases.c.h" + #line 4876 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index d1057e34275add..aa1db721d1ae71 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -866,9 +866,11 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) +#define HAS_JUMP_FLAG (8) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) +#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG)) struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -937,7 +939,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [GET_AITER] = { true, INSTR_FMT_IX, 0 }, [GET_ANEXT] = { true, INSTR_FMT_IX, 0 }, [GET_AWAITABLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1012,16 +1014,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, 0 }, [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG }, - [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [GET_LEN] = { true, INSTR_FMT_IX, 0 }, [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [MATCH_MAPPING] = { true, INSTR_FMT_IX, 0 }, @@ -1029,11 +1031,11 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [MATCH_KEYS] = { true, INSTR_FMT_IX, 0 }, [GET_ITER] = { true, INSTR_FMT_IX, 0 }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX, 0 }, - [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, - [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, - [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, 0 }, [BEFORE_WITH] = { true, INSTR_FMT_IX, 0 }, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 544568e0294e55..723996bd8f7696 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -226,7 +226,7 @@ def assign(self, dst: StackEffect, src: StackEffect): def cast(self, dst: StackEffect, src: StackEffect) -> str: return f"({dst.type or 'PyObject *'})" if src.type != dst.type else "" -INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME'] +INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME', 'HAS_JUMP'] @dataclasses.dataclass class Instruction: @@ -281,6 +281,7 @@ def __init__(self, inst: parser.InstDef): 'HAS_ARG' : variable_used(inst, "oparg"), 'HAS_CONST': variable_used(inst, "FRAME_CO_CONSTS"), 'HAS_NAME' : variable_used(inst, "FRAME_CO_NAMES"), + 'HAS_JUMP' : variable_used(inst, "JUMPBY"), } assert set(flag_data.keys()) == set(INSTRUCTION_FLAGS) self.flags = 0 From 698a0da7d440856a90b45964e9082b5a55387b80 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Jun 2023 01:31:45 +0200 Subject: [PATCH 053/446] gh-105751: Cleanup test_ctypes imports (#105803) * Move imports at top level and sort imports. * Replace c_buffer() with create_string_buffer(): c_buffer is a deprecated alias. * PEP 8: Add empty lines for readability between imports and classes. --- Lib/test/test_ctypes/test_anon.py | 2 + Lib/test/test_ctypes/test_array_in_pointer.py | 10 ++- Lib/test/test_ctypes/test_as_parameter.py | 10 +-- Lib/test/test_ctypes/test_bitfields.py | 10 +-- Lib/test/test_ctypes/test_buffers.py | 4 +- Lib/test/test_ctypes/test_bytes.py | 3 +- Lib/test/test_ctypes/test_byteswap.py | 14 +++-- Lib/test/test_ctypes/test_callbacks.py | 19 +++--- Lib/test/test_ctypes/test_cast.py | 5 +- Lib/test/test_ctypes/test_cfuncs.py | 5 +- Lib/test/test_ctypes/test_checkretval.py | 5 +- Lib/test/test_ctypes/test_errno.py | 8 ++- Lib/test/test_ctypes/test_frombuffer.py | 9 ++- Lib/test/test_ctypes/test_funcptr.py | 5 +- Lib/test/test_ctypes/test_functions.py | 22 +++---- Lib/test/test_ctypes/test_incomplete.py | 7 +-- Lib/test/test_ctypes/test_internals.py | 9 ++- Lib/test/test_ctypes/test_keeprefs.py | 12 +++- Lib/test/test_ctypes/test_libc.py | 7 ++- Lib/test/test_ctypes/test_loading.py | 16 ++--- Lib/test/test_ctypes/test_macholib.py | 10 +-- Lib/test/test_ctypes/test_memfunctions.py | 4 +- Lib/test/test_ctypes/test_numbers.py | 19 +++--- Lib/test/test_ctypes/test_objects.py | 7 ++- Lib/test/test_ctypes/test_parameters.py | 63 +++++-------------- Lib/test/test_ctypes/test_pep3118.py | 15 +++-- Lib/test/test_ctypes/test_pickling.py | 11 +++- Lib/test/test_ctypes/test_pointers.py | 19 +++--- Lib/test/test_ctypes/test_prototypes.py | 27 ++++---- Lib/test/test_ctypes/test_python_api.py | 18 ++---- Lib/test/test_ctypes/test_random_things.py | 7 ++- Lib/test/test_ctypes/test_refcounts.py | 10 +-- Lib/test/test_ctypes/test_repr.py | 6 +- Lib/test/test_ctypes/test_returnfuncptrs.py | 3 +- Lib/test/test_ctypes/test_slicing.py | 3 +- Lib/test/test_ctypes/test_stringptr.py | 29 +++++---- Lib/test/test_ctypes/test_strings.py | 12 ++-- Lib/test/test_ctypes/test_struct_fields.py | 2 + Lib/test/test_ctypes/test_structures.py | 10 ++- .../test_ctypes/test_unaligned_structures.py | 3 + Lib/test/test_ctypes/test_unicode.py | 4 +- Lib/test/test_ctypes/test_values.py | 11 ++-- Lib/test/test_ctypes/test_varsize_struct.py | 4 +- Lib/test/test_ctypes/test_win32.py | 6 +- Lib/test/test_ctypes/test_wintypes.py | 5 +- 45 files changed, 250 insertions(+), 240 deletions(-) diff --git a/Lib/test/test_ctypes/test_anon.py b/Lib/test/test_ctypes/test_anon.py index 704f7a3d38a5ac..b36397b510fefe 100644 --- a/Lib/test/test_ctypes/test_anon.py +++ b/Lib/test/test_ctypes/test_anon.py @@ -2,6 +2,7 @@ import test.support from ctypes import c_int, Union, Structure, sizeof + class AnonTest(unittest.TestCase): def test_anon(self): @@ -69,5 +70,6 @@ class Y(Structure): self.assertEqual(Y._.offset, sizeof(c_int)) self.assertEqual(Y.y.offset, sizeof(c_int) * 2) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_array_in_pointer.py b/Lib/test/test_ctypes/test_array_in_pointer.py index a149aa9463f30c..b7c96b2fa49910 100644 --- a/Lib/test/test_ctypes/test_array_in_pointer.py +++ b/Lib/test/test_ctypes/test_array_in_pointer.py @@ -1,21 +1,24 @@ +import binascii +import re import unittest from ctypes import c_byte, Structure, POINTER, cast -from binascii import hexlify -import re + def dump(obj): # helper function to dump memory contents in hex, with a hyphen # between the bytes. - h = hexlify(memoryview(obj)).decode() + h = binascii.hexlify(memoryview(obj)).decode() return re.sub(r"(..)", r"\1-", h)[:-1] class Value(Structure): _fields_ = [("val", c_byte)] + class Container(Structure): _fields_ = [("pvalues", POINTER(Value))] + class Test(unittest.TestCase): def test(self): # create an array of 4 values @@ -60,5 +63,6 @@ def test_2(self): ([1, 2, 3, 4], "01-02-03-04") ) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index 33b7bd3fadeaae..e842d526c53af0 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -16,9 +16,11 @@ # fake to enable this test on Linux CALLBACK_FUNCTYPE = CFUNCTYPE + class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] + class BasicWrapTestCase(unittest.TestCase): def wrap(self, param): return param @@ -71,8 +73,6 @@ def callback(v): f(self.wrap(2**18), self.wrap(cb)) self.assertEqual(args, expected) - ################################################################ - def test_callbacks(self): f = dll._testfunc_callback_i_if f.restype = c_int @@ -194,8 +194,6 @@ class S8I(Structure): (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) def test_recursive_as_param(self): - from ctypes import c_int - class A(object): pass @@ -205,8 +203,6 @@ class A(object): c_int.from_param(a) -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - class AsParamWrapper(object): def __init__(self, param): self._as_parameter_ = param @@ -214,7 +210,6 @@ def __init__(self, param): class AsParamWrapperTestCase(BasicWrapTestCase): wrap = AsParamWrapper -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class AsParamPropertyWrapper(object): def __init__(self, param): @@ -227,7 +222,6 @@ def getParameter(self): class AsParamPropertyWrapperTestCase(BasicWrapTestCase): wrap = AsParamPropertyWrapper -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_bitfields.py b/Lib/test/test_ctypes/test_bitfields.py index 9ffa634dbf707b..d8eb2d668a6a93 100644 --- a/Lib/test/test_ctypes/test_bitfields.py +++ b/Lib/test/test_ctypes/test_bitfields.py @@ -1,13 +1,13 @@ +import _ctypes_test +import os +import unittest from ctypes import (CDLL, Structure, sizeof, POINTER, byref, alignment, LittleEndianStructure, BigEndianStructure, c_byte, c_ubyte, c_char, c_char_p, c_void_p, c_wchar, c_uint32, c_uint64, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong) from test import support -import unittest -import os -import _ctypes_test class BITS(Structure): _fields_ = [("A", c_int, 1), @@ -56,6 +56,7 @@ def test_shorts(self): setattr(b, name, i) self.assertEqual(getattr(b, name), func(byref(b), name.encode('ascii'))) + signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong) unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong) int_types = unsigned_int_types + signed_int_types @@ -117,7 +118,6 @@ class X(Structure): x.a, x.b = 0, -1 self.assertEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0)) - def fail_fields(self, *fields): return self.get_except(type(Structure), "X", (), {"_fields_": fields}) @@ -194,7 +194,6 @@ class X(Structure): self.assertEqual(X.b.offset, sizeof(c_short)*1) self.assertEqual(X.c.offset, sizeof(c_short)*2) - def get_except(self, func, *args, **kw): try: func(*args, **kw) @@ -291,5 +290,6 @@ class Big(BigEndianStructure): x.c = 2 self.assertEqual(b, b'\xab\xcd\xef\x12') + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_buffers.py b/Lib/test/test_ctypes/test_buffers.py index e446f9e85f9223..468f41eb7cf4ac 100644 --- a/Lib/test/test_ctypes/test_buffers.py +++ b/Lib/test/test_ctypes/test_buffers.py @@ -1,9 +1,9 @@ +import unittest from ctypes import (create_string_buffer, create_unicode_buffer, sizeof, c_char, c_wchar) -import unittest -class StringBufferTestCase(unittest.TestCase): +class StringBufferTestCase(unittest.TestCase): def test_buffer(self): b = create_string_buffer(32) self.assertEqual(len(b), 32) diff --git a/Lib/test/test_ctypes/test_bytes.py b/Lib/test/test_ctypes/test_bytes.py index 3538ed7d7197cc..fa11e1bbd49faf 100644 --- a/Lib/test/test_ctypes/test_bytes.py +++ b/Lib/test/test_ctypes/test_bytes.py @@ -1,8 +1,10 @@ """Test where byte objects are accepted""" import sys import unittest +from _ctypes import _SimpleCData from ctypes import Structure, c_char, c_char_p, c_wchar, c_wchar_p + class BytesTest(unittest.TestCase): def test_c_char(self): x = c_char(b"x") @@ -55,7 +57,6 @@ class X(Structure): @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') def test_BSTR(self): - from _ctypes import _SimpleCData class BSTR(_SimpleCData): _type_ = "X" diff --git a/Lib/test/test_ctypes/test_byteswap.py b/Lib/test/test_ctypes/test_byteswap.py index 7507c07d8a8a95..2986e8a177a405 100644 --- a/Lib/test/test_ctypes/test_byteswap.py +++ b/Lib/test/test_ctypes/test_byteswap.py @@ -1,6 +1,9 @@ -import sys, unittest, struct, math, ctypes -from binascii import hexlify - +import binascii +import ctypes +import math +import struct +import sys +import unittest from ctypes import (Structure, Union, LittleEndianUnion, BigEndianUnion, BigEndianStructure, LittleEndianStructure, POINTER, sizeof, cast, @@ -9,8 +12,10 @@ c_long, c_ulong, c_longlong, c_ulonglong, c_uint32, c_float, c_double) + def bin(s): - return hexlify(memoryview(s)).decode().upper() + return binascii.hexlify(memoryview(s)).decode().upper() + # Each *simple* type that supports different byte orders has an # __ctype_be__ attribute that specifies the same type in BIG ENDIAN @@ -366,5 +371,6 @@ class TestUnion(parent): self.assertEqual(s.point.x, 1) self.assertEqual(s.point.y, 2) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 50c2650cb345ab..582677b832e5cb 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -1,24 +1,25 @@ +import _ctypes_test +import ctypes import functools +import gc +import math import sys import unittest -from test import support - -import ctypes +from _ctypes import CTYPES_MAX_ARGCOUNT from ctypes import (CDLL, cdll, Structure, CFUNCTYPE, ArgumentError, POINTER, sizeof, c_byte, c_ubyte, c_char, c_char_p, c_short, c_ushort, c_int, c_uint, c_long, c_longlong, c_ulonglong, c_ulong, c_float, c_double, c_longdouble, py_object) -from _ctypes import CTYPES_MAX_ARGCOUNT -import _ctypes_test +from ctypes.util import find_library +from test import support class Callbacks(unittest.TestCase): functype = CFUNCTYPE ## def tearDown(self): -## import gc ## gc.collect() def callback(self, *args): @@ -81,7 +82,6 @@ def test_ulonglong(self): def test_float(self): # only almost equal: double -> float -> double - import math self.check_type(c_float, math.e) self.check_type(c_float, -math.e) @@ -138,7 +138,6 @@ def func(self): pass def __init__(self): self.v = proto(self.func) - import gc for i in range(32): X() gc.collect() @@ -147,7 +146,6 @@ def __init__(self): self.assertEqual(len(live), 0) def test_issue12483(self): - import gc class Nasty: def __del__(self): gc.collect() @@ -172,8 +170,6 @@ class StdcallCallbacks(Callbacks): functype = ctypes.WINFUNCTYPE -################################################################ - class SampleCallbacksTestCase(unittest.TestCase): def test_integrate(self): @@ -197,7 +193,6 @@ def func(x): self.assertLess(diff, 0.01, "%s not less than 0.01" % diff) def test_issue_8959_a(self): - from ctypes.util import find_library libc_path = find_library("c") if not libc_path: self.skipTest('could not find libc') diff --git a/Lib/test/test_ctypes/test_cast.py b/Lib/test/test_ctypes/test_cast.py index abff120d8b0e36..604f44f03d61b2 100644 --- a/Lib/test/test_ctypes/test_cast.py +++ b/Lib/test/test_ctypes/test_cast.py @@ -4,8 +4,8 @@ c_void_p, c_char_p, c_wchar_p, c_byte, c_short, c_int) -class Test(unittest.TestCase): +class Test(unittest.TestCase): def test_array2pointer(self): array = (c_int * 3)(42, 17, 2) @@ -80,7 +80,7 @@ def test_char_p(self): def test_wchar_p(self): s = c_wchar_p("hiho") self.assertEqual(cast(cast(s, c_void_p), c_wchar_p).value, - "hiho") + "hiho") def test_bad_type_arg(self): # The type argument must be a ctypes pointer type. @@ -95,5 +95,6 @@ class MyUnion(Union): _fields_ = [("a", c_int)] self.assertRaises(TypeError, cast, array, MyUnion) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_cfuncs.py b/Lib/test/test_ctypes/test_cfuncs.py index 6969aed8189139..6ff0878a35da2f 100644 --- a/Lib/test/test_ctypes/test_cfuncs.py +++ b/Lib/test/test_ctypes/test_cfuncs.py @@ -1,11 +1,11 @@ -import unittest +import _ctypes_test import ctypes +import unittest from ctypes import (CDLL, c_byte, c_ubyte, c_char, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble) -import _ctypes_test class CFunctions(unittest.TestCase): @@ -190,6 +190,7 @@ def test_void(self): self.assertEqual(self._dll.tv_i(-42), None) self.assertEqual(self.S(), -42) + # The following repeats the above tests with stdcall functions (where # they are available) if hasattr(ctypes, 'WinDLL'): diff --git a/Lib/test/test_ctypes/test_checkretval.py b/Lib/test/test_ctypes/test_checkretval.py index 176102d5a89e76..5dc9e25aa38226 100644 --- a/Lib/test/test_ctypes/test_checkretval.py +++ b/Lib/test/test_ctypes/test_checkretval.py @@ -1,3 +1,4 @@ +import _ctypes_test import ctypes import unittest from ctypes import CDLL, c_int @@ -11,10 +12,7 @@ def _check_retval_(value): class Test(unittest.TestCase): - def test_checkretval(self): - - import _ctypes_test dll = CDLL(_ctypes_test.__file__) self.assertEqual(42, dll._testfunc_p_p(42)) @@ -34,6 +32,5 @@ def test_oledll(self): self.assertRaises(OSError, oleaut32.CreateTypeLib2, 0, None, None) - if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_errno.py b/Lib/test/test_ctypes/test_errno.py index 3376322299d29e..65d99c1e492abe 100644 --- a/Lib/test/test_ctypes/test_errno.py +++ b/Lib/test/test_ctypes/test_errno.py @@ -1,10 +1,12 @@ -import unittest, os, errno -import threading - import ctypes +import errno +import os +import threading +import unittest from ctypes import CDLL, c_int, c_char_p, c_wchar_p, get_errno, set_errno from ctypes.util import find_library + class Test(unittest.TestCase): def test_open(self): libc_name = find_library("c") diff --git a/Lib/test/test_ctypes/test_frombuffer.py b/Lib/test/test_ctypes/test_frombuffer.py index e3e1267387848e..d4e161f864d409 100644 --- a/Lib/test/test_ctypes/test_frombuffer.py +++ b/Lib/test/test_ctypes/test_frombuffer.py @@ -1,7 +1,10 @@ import array import gc import unittest -from ctypes import Structure, Union, Array, sizeof, c_char, c_int +from ctypes import (Structure, Union, Array, sizeof, + _Pointer, _SimpleCData, _CFuncPtr, + c_char, c_int) + class X(Structure): _fields_ = [("c_int", c_int)] @@ -9,6 +12,7 @@ class X(Structure): def __init__(self): self._init_called = True + class Test(unittest.TestCase): def test_from_buffer(self): a = array.array("i", range(16)) @@ -121,8 +125,6 @@ def test_from_buffer_copy_with_offset(self): (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int)) def test_abstract(self): - from ctypes import _Pointer, _SimpleCData, _CFuncPtr - self.assertRaises(TypeError, Array.from_buffer, bytearray(10)) self.assertRaises(TypeError, Structure.from_buffer, bytearray(10)) self.assertRaises(TypeError, Union.from_buffer, bytearray(10)) @@ -137,5 +139,6 @@ def test_abstract(self): self.assertRaises(TypeError, _Pointer.from_buffer_copy, b"123") self.assertRaises(TypeError, _SimpleCData.from_buffer_copy, b"123") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_funcptr.py b/Lib/test/test_ctypes/test_funcptr.py index 72684d6d1cd19b..0ea3f3581bbaa6 100644 --- a/Lib/test/test_ctypes/test_funcptr.py +++ b/Lib/test/test_ctypes/test_funcptr.py @@ -1,9 +1,10 @@ import _ctypes_test import ctypes import unittest -from ctypes import (CDLL, Structure, CFUNCTYPE, sizeof, +from ctypes import (CDLL, Structure, CFUNCTYPE, sizeof, _CFuncPtr, c_void_p, c_char_p, c_char, c_int, c_uint, c_long) + try: WINFUNCTYPE = ctypes.WINFUNCTYPE except AttributeError: @@ -127,8 +128,6 @@ def c_string(init): self.assertEqual(strtok(None, b"\n"), None) def test_abstract(self): - from ctypes import _CFuncPtr - self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid") diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index 7979f0e36b301c..f8591463c18ad0 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -1,17 +1,14 @@ -""" -Here is probably the place to write the docs, since the test-cases -show how the type behave. - -Later... -""" - +import _ctypes_test import ctypes +import sys +import unittest from ctypes import (CDLL, Structure, Array, CFUNCTYPE, byref, POINTER, pointer, ArgumentError, c_char, c_wchar, c_byte, c_char_p, c_short, c_int, c_long, c_longlong, c_float, c_double, c_longdouble) -import sys, unittest +from _ctypes import _Pointer, _SimpleCData + try: WINFUNCTYPE = ctypes.WINFUNCTYPE @@ -19,16 +16,20 @@ # fake to enable this test on Linux WINFUNCTYPE = CFUNCTYPE -import _ctypes_test dll = CDLL(_ctypes_test.__file__) if sys.platform == "win32": windll = ctypes.WinDLL(_ctypes_test.__file__) + class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] + + class RECT(Structure): _fields_ = [("left", c_int), ("top", c_int), ("right", c_int), ("bottom", c_int)] + + class FunctionTestCase(unittest.TestCase): def test_mro(self): @@ -44,12 +45,10 @@ class X(object, Array): _length_ = 5 _type_ = "i" - from _ctypes import _Pointer with self.assertRaises(TypeError): class X(object, _Pointer): pass - from _ctypes import _SimpleCData with self.assertRaises(TypeError): class X(object, _SimpleCData): _type_ = "i" @@ -407,5 +406,6 @@ def callback(*args): callback = proto(callback) self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT())) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_incomplete.py b/Lib/test/test_ctypes/test_incomplete.py index 552effaa3db973..9f859793d88a22 100644 --- a/Lib/test/test_ctypes/test_incomplete.py +++ b/Lib/test/test_ctypes/test_incomplete.py @@ -3,13 +3,9 @@ import warnings from ctypes import Structure, POINTER, pointer, c_char_p -################################################################ -# -# The incomplete pointer example from the tutorial -# +# The incomplete pointer example from the tutorial class TestSetPointerType(unittest.TestCase): - def tearDown(self): # to not leak references, we must clean _pointer_type_cache ctypes._reset_cache() @@ -49,7 +45,6 @@ class cell(Structure): with self.assertWarns(DeprecationWarning): ctypes.SetPointerType(lpcell, cell) -################################################################ if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_internals.py b/Lib/test/test_ctypes/test_internals.py index 06826eb9ebd710..763a5e8b0f0858 100644 --- a/Lib/test/test_ctypes/test_internals.py +++ b/Lib/test/test_ctypes/test_internals.py @@ -1,7 +1,4 @@ # This tests the internal _objects attribute -import sys -import unittest -from ctypes import Structure, POINTER, c_char_p, c_int # XXX This test must be reviewed for correctness!!! @@ -14,6 +11,11 @@ # # What about pointers? +import sys +import unittest +from ctypes import Structure, POINTER, c_char_p, c_int + + class ObjectsTestCase(unittest.TestCase): def assertSame(self, a, b): self.assertEqual(id(a), id(b)) @@ -96,5 +98,6 @@ class X(Structure): ##XXX print x.data[0] ##XXX print x.data._objects + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index 6fb0628ad3b6eb..f93e3f2676945c 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -1,6 +1,8 @@ +import gc import sys import unittest -from ctypes import Structure, POINTER, pointer, c_char_p, c_int +from ctypes import (Structure, POINTER, pointer, _pointer_type_cache, + c_char_p, c_int) class SimpleTestCase(unittest.TestCase): @@ -20,6 +22,7 @@ def test_ccharp(self): x = c_char_p(b"spam") self.assertEqual(x._objects, b"spam") + class StructureTestCase(unittest.TestCase): def test_cint_struct(self): class X(Structure): @@ -66,6 +69,7 @@ class RECT(Structure): r.lr = POINT() self.assertEqual(r._objects, {'0': {}, '1': {}}) + class ArrayTestCase(unittest.TestCase): def test_cint_array(self): INTARR = c_int * 3 @@ -89,12 +93,14 @@ class X(Structure): x.a = ia self.assertEqual(x._objects, {'1': {}}) + class PointerTestCase(unittest.TestCase): def test_p_cint(self): i = c_int(42) x = pointer(i) self.assertEqual(x._objects, {'1': i}) + class DeletePointerTestCase(unittest.TestCase): @unittest.skip('test disabled') def test_X(self): @@ -112,7 +118,6 @@ class X(Structure): ## del x ## print "2?", sys.getrefcount(i) ## del i - import gc gc.collect() for i in range(320): c_int(99) @@ -126,6 +131,7 @@ class X(Structure): print("+" * 42) print(x._objects) + class PointerToStructure(unittest.TestCase): def test(self): class POINT(Structure): @@ -147,8 +153,8 @@ class RECT(Structure): # to avoid leaking when tests are run several times # clean up the types left in the cache. - from ctypes import _pointer_type_cache del _pointer_type_cache[POINT] + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_libc.py b/Lib/test/test_ctypes/test_libc.py index 8664529f094476..09c76db0bd0b17 100644 --- a/Lib/test/test_ctypes/test_libc.py +++ b/Lib/test/test_ctypes/test_libc.py @@ -1,10 +1,10 @@ +import _ctypes_test +import math import unittest - from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, c_void_p, c_char, c_int, c_double, c_size_t) -import _ctypes_test lib = CDLL(_ctypes_test.__file__) @@ -12,12 +12,12 @@ def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" return (x > y) - (x < y) + class LibTest(unittest.TestCase): def test_sqrt(self): lib.my_sqrt.argtypes = c_double, lib.my_sqrt.restype = c_double self.assertEqual(lib.my_sqrt(4.0), 2.0) - import math self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) def test_qsort(self): @@ -32,5 +32,6 @@ def sort(a, b): lib.my_qsort(chars, len(chars)-1, sizeof(c_char), comparefunc(sort)) self.assertEqual(chars.raw, b" ,,aaaadmmmnpppsss\x00") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_loading.py b/Lib/test/test_ctypes/test_loading.py index 0cbfcf01c0cf2b..22db97b818c17e 100644 --- a/Lib/test/test_ctypes/test_loading.py +++ b/Lib/test/test_ctypes/test_loading.py @@ -1,3 +1,5 @@ +import _ctypes +import _ctypes_test import ctypes import os import shutil @@ -5,13 +7,14 @@ import sys import test.support import unittest -from test.support import import_helper, os_helper from ctypes import CDLL, cdll, addressof, c_void_p, c_char_p from ctypes.util import find_library +from test.support import import_helper, os_helper libc_name = None + def setUpModule(): global libc_name if os.name == "nt": @@ -24,6 +27,7 @@ def setUpModule(): if test.support.verbose: print("libc_name is", libc_name) + class LoaderTest(unittest.TestCase): unknowndll = "xxrandomnamexx" @@ -33,7 +37,6 @@ def test_load(self): test_lib = libc_name else: if os.name == "nt": - import _ctypes_test test_lib = _ctypes_test.__file__ else: self.skipTest('could not find library to load') @@ -83,7 +86,6 @@ def test_load_library(self): @unittest.skipUnless(os.name == "nt", 'test specific to Windows') def test_load_ordinal_functions(self): - import _ctypes_test dll = ctypes.WinDLL(_ctypes_test.__file__) # We load the same function both via ordinal and name func_ord = dll[2] @@ -99,14 +101,13 @@ def test_load_ordinal_functions(self): @unittest.skipUnless(os.name == "nt", 'Windows-specific test') def test_1703286_A(self): - from _ctypes import LoadLibrary, FreeLibrary # On winXP 64-bit, advapi32 loads at an address that does # NOT fit into a 32-bit integer. FreeLibrary must be able # to accept this address. # These are tests for https://bugs.python.org/issue1703286 - handle = LoadLibrary("advapi32") - FreeLibrary(handle) + handle = _ctypes.LoadLibrary("advapi32") + _ctypes.FreeLibrary(handle) @unittest.skipUnless(os.name == "nt", 'Windows-specific test') def test_1703286_B(self): @@ -114,7 +115,6 @@ def test_1703286_B(self): # above, the (arbitrarily selected) CloseEventLog function # also has a high address. 'call_function' should accept # addresses so large. - from _ctypes import call_function advapi32 = ctypes.windll.advapi32 # Calling CloseEventLog with a NULL argument should fail, @@ -128,7 +128,7 @@ def test_1703286_B(self): self.assertTrue(proc) # This is the real test: call the function via 'call_function' - self.assertEqual(0, call_function(proc, (None,))) + self.assertEqual(0, _ctypes.call_function(proc, (None,))) @unittest.skipUnless(os.name == "nt", 'test specific to Windows') diff --git a/Lib/test/test_ctypes/test_macholib.py b/Lib/test/test_ctypes/test_macholib.py index bc75f1a05a8c37..9d90617995623d 100644 --- a/Lib/test/test_ctypes/test_macholib.py +++ b/Lib/test/test_ctypes/test_macholib.py @@ -1,7 +1,3 @@ -import os -import sys -import unittest - # Bob Ippolito: # # Ok.. the code to find the filename for __getattr__ should look @@ -31,10 +27,15 @@ # # -bob +import os +import sys +import unittest + from ctypes.macholib.dyld import dyld_find from ctypes.macholib.dylib import dylib_info from ctypes.macholib.framework import framework_info + def find_lib(name): possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name] for dylib in possible: @@ -106,5 +107,6 @@ def test_framework_info(self): self.assertEqual(framework_info('P/F.framework/Versions/A/F_debug'), d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug')) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py index 9d8e156ad5e00e..2ff95f619e0895 100644 --- a/Lib/test/test_ctypes/test_memfunctions.py +++ b/Lib/test/test_ctypes/test_memfunctions.py @@ -1,12 +1,13 @@ import sys -from test import support import unittest +from test import support from ctypes import (POINTER, sizeof, cast, create_string_buffer, string_at, create_unicode_buffer, wstring_at, memmove, memset, c_char_p, c_byte, c_ubyte, c_wchar) + class MemFunctionsTest(unittest.TestCase): @unittest.skip('test disabled') def test_overflow(self): @@ -77,5 +78,6 @@ def test_wstring_at(self): self.assertEqual(wstring_at(a, 16), "Hello, World\0\0\0\0") self.assertEqual(wstring_at(a, 0), "") + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 061876f9f776d6..052900f519c0b9 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -1,13 +1,14 @@ +import array import struct import sys import unittest -from array import array from operator import truth from ctypes import (byref, sizeof, alignment, _SimpleCData, c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble, c_bool) + def valid_ranges(*types): # given a sequence of numeric types, collect their _type_ # attribute, which is a single format character compatible with @@ -25,6 +26,7 @@ def valid_ranges(*types): result.append((min(a, b, c, d), max(a, b, c, d))) return result + ArgType = type(byref(c_int(0))) unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong] @@ -36,7 +38,6 @@ def valid_ranges(*types): signed_ranges = valid_ranges(*signed_types) bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] -################################################################ class NumberTestCase(unittest.TestCase): @@ -152,10 +153,10 @@ def test_int_from_address(self): # the array module doesn't support all format codes # (no 'q' or 'Q') try: - array(t._type_) + array.array(t._type_) except ValueError: continue - a = array(t._type_, [100]) + a = array.array(t._type_, [100]) # v now is an integer at an 'external' memory location v = t.from_address(a.buffer_info()[0]) @@ -169,7 +170,7 @@ def test_int_from_address(self): def test_float_from_address(self): for t in float_types: - a = array(t._type_, [3.14]) + a = array.array(t._type_, [3.14]) v = t.from_address(a.buffer_info()[0]) self.assertEqual(v.value, a[0]) self.assertIs(type(v), t) @@ -178,7 +179,7 @@ def test_float_from_address(self): self.assertIs(type(v), t) def test_char_from_address(self): - a = array('b', [0]) + a = array.array('b', [0]) a[0] = ord('x') v = c_char.from_address(a.buffer_info()[0]) self.assertEqual(v.value, b'x') @@ -190,7 +191,7 @@ def test_char_from_address(self): # array does not support c_bool / 't' @unittest.skip('test disabled') def test_bool_from_address(self): - a = array(c_bool._type_, [True]) + a = array.array(c_bool._type_, [True]) v = t.from_address(a.buffer_info()[0]) self.assertEqual(v.value, a[0]) self.assertEqual(type(v) is t) @@ -217,10 +218,12 @@ def test_float_overflow(self): def test_perf(self): check_perf() + class c_int_S(_SimpleCData): _type_ = "i" __slots__ = [] + def run_test(rep, msg, func, arg=None): ## items = [None] * rep items = range(rep) @@ -237,6 +240,7 @@ def run_test(rep, msg, func, arg=None): stop = clock() print("%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep))) + def check_perf(): # Construct 5 objects from ctypes import c_int @@ -268,6 +272,7 @@ def check_perf(): # c_int_S(): 9.87 us # c_int_S(999): 9.85 us + if __name__ == '__main__': ## check_perf() unittest.main() diff --git a/Lib/test/test_ctypes/test_objects.py b/Lib/test/test_ctypes/test_objects.py index 78b1634115bdb4..23c92b01a11107 100644 --- a/Lib/test/test_ctypes/test_objects.py +++ b/Lib/test/test_ctypes/test_objects.py @@ -51,17 +51,18 @@ >>> x.array._b_base_._objects {'0:2': b'spam spam spam'} >>> - ''' -import unittest, doctest - +import doctest +import unittest import test.test_ctypes.test_objects + class TestCase(unittest.TestCase): def test(self): failures, tests = doctest.testmod(test.test_ctypes.test_objects) self.assertFalse(failures, 'doctests failed, see output above') + if __name__ == '__main__': doctest.testmod(test.test_ctypes.test_objects) diff --git a/Lib/test/test_ctypes/test_parameters.py b/Lib/test/test_ctypes/test_parameters.py index 02a2bc3839a6bb..f43819f004996c 100644 --- a/Lib/test/test_ctypes/test_parameters.py +++ b/Lib/test/test_ctypes/test_parameters.py @@ -1,8 +1,22 @@ +import _ctypes_test import unittest import test.support +from ctypes import (CDLL, PyDLL, ArgumentError, + Structure, Array, Union, + _Pointer, _SimpleCData, _CFuncPtr, + POINTER, pointer, byref, + c_void_p, c_char_p, c_wchar_p, py_object, + c_bool, + c_char, c_wchar, + c_byte, c_ubyte, + c_short, c_ushort, + c_int, c_uint, + c_long, c_ulong, + c_longlong, c_ulonglong, + c_float, c_double, c_longdouble) -class SimpleTypesTestCase(unittest.TestCase): +class SimpleTypesTestCase(unittest.TestCase): def setUp(self): try: from _ctypes import set_conversion_mode @@ -20,7 +34,6 @@ def tearDown(self): set_conversion_mode(*self.prev_conv_mode) def test_subclasses(self): - from ctypes import c_void_p, c_char_p # ctypes 0.9.5 and before did overwrite from_param in SimpleType_new class CVOIDP(c_void_p): def from_param(cls, value): @@ -36,8 +49,6 @@ def from_param(cls, value): self.assertEqual(CCHARP.from_param("abc"), "abcabcabcabc") def test_subclasses_c_wchar_p(self): - from ctypes import c_wchar_p - class CWCHARP(c_wchar_p): def from_param(cls, value): return value * 3 @@ -47,8 +58,6 @@ def from_param(cls, value): # XXX Replace by c_char_p tests def test_cstrings(self): - from ctypes import c_char_p - # c_char_p.from_param on a Python String packs the string # into a cparam object s = b"123" @@ -65,8 +74,6 @@ def test_cstrings(self): self.assertIs(c_char_p.from_param(a), a) def test_cw_strings(self): - from ctypes import c_wchar_p - c_wchar_p.from_param("123") self.assertRaises(TypeError, c_wchar_p.from_param, 42) @@ -76,16 +83,12 @@ def test_cw_strings(self): self.assertEqual(type(pa), c_wchar_p) def test_c_char(self): - from ctypes import c_char - with self.assertRaises(TypeError) as cm: c_char.from_param(b"abc") self.assertEqual(str(cm.exception), "one character bytes, bytearray or integer expected") def test_c_wchar(self): - from ctypes import c_wchar - with self.assertRaises(TypeError) as cm: c_wchar.from_param("abc") self.assertEqual(str(cm.exception), @@ -98,7 +101,6 @@ def test_c_wchar(self): "unicode string expected instead of int instance") def test_int_pointers(self): - from ctypes import c_short, c_uint, c_int, c_long, POINTER, pointer LPINT = POINTER(c_int) ## p = pointer(c_int(42)) @@ -117,7 +119,6 @@ def test_int_pointers(self): def test_byref_pointer(self): # The from_param class method of POINTER(typ) classes accepts what is # returned by byref(obj), it type(obj) == typ - from ctypes import c_short, c_uint, c_int, c_long, POINTER, byref LPINT = POINTER(c_int) LPINT.from_param(byref(c_int(42))) @@ -129,7 +130,6 @@ def test_byref_pointer(self): def test_byref_pointerpointer(self): # See above - from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref LPLPINT = POINTER(POINTER(c_int)) LPLPINT.from_param(byref(pointer(c_int(42)))) @@ -140,7 +140,6 @@ def test_byref_pointerpointer(self): self.assertRaises(TypeError, LPLPINT.from_param, byref(pointer(c_uint(22)))) def test_array_pointers(self): - from ctypes import c_short, c_uint, c_int, c_long, POINTER INTARRAY = c_int * 3 ia = INTARRAY() self.assertEqual(len(ia), 3) @@ -155,9 +154,6 @@ def test_array_pointers(self): self.assertRaises(TypeError, LPINT.from_param, c_uint*3) def test_noctypes_argtype(self): - import _ctypes_test - from ctypes import CDLL, c_void_p, ArgumentError - func = CDLL(_ctypes_test.__file__)._testfunc_p_p func.restype = c_void_p # TypeError: has no from_param method @@ -189,9 +185,6 @@ def from_param(cls, obj): self.assertRaises(ArgumentError, func, 99) def test_abstract(self): - from ctypes import (Array, Structure, Union, _Pointer, - _SimpleCData, _CFuncPtr) - self.assertRaises(TypeError, Array.from_param, 42) self.assertRaises(TypeError, Structure.from_param, 42) self.assertRaises(TypeError, Union.from_param, 42) @@ -203,7 +196,6 @@ def test_abstract(self): def test_issue31311(self): # __setstate__ should neither raise a SystemError nor crash in case # of a bad __dict__. - from ctypes import Structure class BadStruct(Structure): @property @@ -220,27 +212,6 @@ def __dict__(self): WorseStruct().__setstate__({}, b'foo') def test_parameter_repr(self): - from ctypes import ( - c_bool, - c_char, - c_wchar, - c_byte, - c_ubyte, - c_short, - c_ushort, - c_int, - c_uint, - c_long, - c_ulong, - c_longlong, - c_ulonglong, - c_float, - c_double, - c_longdouble, - c_char_p, - c_wchar_p, - c_void_p, - ) self.assertRegex(repr(c_bool.from_param(True)), r"^$") self.assertEqual(repr(c_char.from_param(97)), "") self.assertRegex(repr(c_wchar.from_param('a')), r"^$") @@ -265,9 +236,6 @@ def test_parameter_repr(self): @test.support.cpython_only def test_from_param_result_refcount(self): # Issue #99952 - import _ctypes_test - from ctypes import PyDLL, c_int, c_void_p, py_object, Structure - class X(Structure): """This struct size is <= sizeof(void*).""" _fields_ = [("a", c_void_p)] @@ -314,7 +282,6 @@ def from_param(cls, value): self.assertEqual(trace, [1, 2, 3, 4, 5]) -################################################################ if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index c8eb584858ca9d..caecbc8def8815 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -1,3 +1,5 @@ +import re +import sys import unittest from ctypes import (CFUNCTYPE, POINTER, sizeof, Union, Structure, LittleEndianStructure, BigEndianStructure, @@ -5,7 +7,7 @@ c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_uint64, c_bool, c_float, c_double, c_longdouble, py_object) -import re, sys + if sys.byteorder == "little": THIS_ENDIAN = "<" @@ -14,6 +16,7 @@ THIS_ENDIAN = ">" OTHER_ENDIAN = "<" + def normalize(format): # Remove current endian specifier and white space from a format # string @@ -22,8 +25,8 @@ def normalize(format): format = format.replace(OTHER_ENDIAN, THIS_ENDIAN) return re.sub(r"\s", "", format) -class Test(unittest.TestCase): +class Test(unittest.TestCase): def test_native_types(self): for tp, fmt, shape, itemtp in native_types: ob = tp() @@ -80,6 +83,7 @@ def test_endian_types(self): print(tp) raise + # define some structure classes class Point(Structure): @@ -124,6 +128,7 @@ class Complete(Structure): PComplete = POINTER(Complete) Complete._fields_ = [("a", c_long)] + ################################################################ # # This table contains format strings as they look on little endian @@ -233,17 +238,16 @@ class Complete(Structure): ] + class BEPoint(BigEndianStructure): _fields_ = [("x", c_long), ("y", c_long)] class LEPoint(LittleEndianStructure): _fields_ = [("x", c_long), ("y", c_long)] -################################################################ -# + # This table contains format strings as they really look, on both big # and little endian machines. -# endian_types = [ (BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint), (LEPoint * 1, "T{= 0 return a + def c_wbuffer(init): n = len(init) + 1 return (c_wchar * n)(*init) -class CharPointersTestCase(unittest.TestCase): +class CharPointersTestCase(unittest.TestCase): def setUp(self): func = testdll._testfunc_p_p func.restype = c_long @@ -102,7 +105,7 @@ def test_POINTER_c_char_arg(self): self.assertEqual(None, func(c_char_p(None))) self.assertEqual(b"123", func(c_char_p(b"123"))) - self.assertEqual(b"123", func(c_buffer(b"123"))) + self.assertEqual(b"123", func(create_string_buffer(b"123"))) ca = c_char(b"a") self.assertEqual(ord(b"a"), func(pointer(ca))[0]) self.assertEqual(ord(b"a"), func(byref(ca))[0]) @@ -117,7 +120,7 @@ def test_c_char_p_arg(self): self.assertEqual(None, func(c_char_p(None))) self.assertEqual(b"123", func(c_char_p(b"123"))) - self.assertEqual(b"123", func(c_buffer(b"123"))) + self.assertEqual(b"123", func(create_string_buffer(b"123"))) ca = c_char(b"a") self.assertEqual(ord(b"a"), func(pointer(ca))[0]) self.assertEqual(ord(b"a"), func(byref(ca))[0]) @@ -132,7 +135,7 @@ def test_c_void_p_arg(self): self.assertEqual(b"123", func(c_char_p(b"123"))) self.assertEqual(None, func(c_char_p(None))) - self.assertEqual(b"123", func(c_buffer(b"123"))) + self.assertEqual(b"123", func(create_string_buffer(b"123"))) ca = c_char(b"a") self.assertEqual(ord(b"a"), func(pointer(ca))[0]) self.assertEqual(ord(b"a"), func(byref(ca))[0]) @@ -162,8 +165,8 @@ class X: func.argtypes = None self.assertEqual(None, func(X())) -class WCharPointersTestCase(unittest.TestCase): +class WCharPointersTestCase(unittest.TestCase): def setUp(self): func = testdll._testfunc_p_p func.restype = c_int @@ -203,6 +206,7 @@ def test_c_wchar_p_arg(self): self.assertEqual("a", func(pointer(ca))[0]) self.assertEqual("a", func(byref(ca))[0]) + class ArrayTest(unittest.TestCase): def test(self): func = testdll._testfunc_ai8 @@ -216,7 +220,6 @@ def test(self): def func(): pass CFUNCTYPE(None, c_int * 3)(func) -################################################################ if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_python_api.py b/Lib/test/test_ctypes/test_python_api.py index c8b81196609f93..77da35855928a4 100644 --- a/Lib/test/test_ctypes/test_python_api.py +++ b/Lib/test/test_ctypes/test_python_api.py @@ -1,20 +1,12 @@ -import unittest +import _ctypes import sys +import unittest from test import support -from ctypes import (pythonapi, POINTER, c_buffer, sizeof, +from ctypes import (pythonapi, POINTER, create_string_buffer, sizeof, py_object, c_char_p, c_char, c_long, c_size_t) -################################################################ -# This section should be moved into ctypes\__init__.py, when it's ready. - -from _ctypes import PyObj_FromPtr - -################################################################ - - class PythonAPITestCase(unittest.TestCase): - def test_PyBytes_FromStringAndSize(self): PyBytes_FromStringAndSize = pythonapi.PyBytes_FromStringAndSize @@ -58,7 +50,7 @@ def test_PyObj_FromPtr(self): s = "abc def ghi jkl" ref = sys.getrefcount(s) # id(python-object) is the address - pyobj = PyObj_FromPtr(id(s)) + pyobj = _ctypes.PyObj_FromPtr(id(s)) self.assertIs(s, pyobj) self.assertEqual(sys.getrefcount(s), ref + 1) @@ -69,7 +61,7 @@ def test_PyOS_snprintf(self): PyOS_snprintf = pythonapi.PyOS_snprintf PyOS_snprintf.argtypes = POINTER(c_char), c_size_t, c_char_p - buf = c_buffer(256) + buf = create_string_buffer(256) PyOS_snprintf(buf, sizeof(buf), b"Hello from %s", b"ctypes") self.assertEqual(buf.value, b"Hello from ctypes") diff --git a/Lib/test/test_ctypes/test_random_things.py b/Lib/test/test_ctypes/test_random_things.py index fcea8e847eb606..65eb53f86475d3 100644 --- a/Lib/test/test_ctypes/test_random_things.py +++ b/Lib/test/test_ctypes/test_random_things.py @@ -1,3 +1,4 @@ +import _ctypes import contextlib import ctypes import sys @@ -10,14 +11,13 @@ def callback_func(arg): 42 / arg raise ValueError(arg) + @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') class call_function_TestCase(unittest.TestCase): # _ctypes.call_function is deprecated and private, but used by # Gary Bishp's readline module. If we have it, we must test it as well. def test(self): - from _ctypes import call_function - kernel32 = ctypes.windll.kernel32 kernel32.LoadLibraryA.restype = c_void_p kernel32.GetProcAddress.argtypes = c_void_p, c_char_p @@ -26,9 +26,10 @@ def test(self): hdll = kernel32.LoadLibraryA(b"kernel32") funcaddr = kernel32.GetProcAddress(hdll, b"GetModuleHandleA") - self.assertEqual(call_function(funcaddr, (None,)), + self.assertEqual(_ctypes.call_function(funcaddr, (None,)), kernel32.GetModuleHandleA(None)) + class CallbackTracbackTestCase(unittest.TestCase): # When an exception is raised in a ctypes callback function, the C # code prints a traceback. diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index b05cad0512c18e..a1fe89105aee9c 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -1,17 +1,18 @@ +import _ctypes_test import ctypes import gc import sys import unittest from test import support + MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int) OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) -import _ctypes_test dll = ctypes.CDLL(_ctypes_test.__file__) -class RefcountTestCase(unittest.TestCase): +class RefcountTestCase(unittest.TestCase): @support.refcount_test def test_1(self): f = dll._testfunc_callback_i_if @@ -34,7 +35,6 @@ def callback(value): self.assertEqual(sys.getrefcount(callback), 2) - @support.refcount_test def test_refcount(self): def func(*args): @@ -82,10 +82,9 @@ class X(ctypes.Structure): gc.collect() self.assertEqual(sys.getrefcount(func), 2) + class AnotherLeak(unittest.TestCase): def test_callback(self): - import sys - proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int) def func(a, b): return a * b * 2 @@ -110,5 +109,6 @@ def func(): for _ in range(10000): func() + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_repr.py b/Lib/test/test_ctypes/test_repr.py index bb6b5ae5e799fd..e7587984a92c45 100644 --- a/Lib/test/test_ctypes/test_repr.py +++ b/Lib/test/test_ctypes/test_repr.py @@ -1,7 +1,8 @@ +import unittest from ctypes import (c_byte, c_short, c_int, c_long, c_longlong, c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong, c_float, c_double, c_longdouble, c_bool, c_char) -import unittest + subclasses = [] for base in [c_byte, c_short, c_int, c_long, c_longlong, @@ -11,11 +12,12 @@ class X(base): pass subclasses.append(X) + class X(c_char): pass -# This test checks if the __repr__ is correct for subclasses of simple types +# This test checks if the __repr__ is correct for subclasses of simple types class ReprTest(unittest.TestCase): def test_numbers(self): for typ in subclasses: diff --git a/Lib/test/test_ctypes/test_returnfuncptrs.py b/Lib/test/test_ctypes/test_returnfuncptrs.py index 6a624133554ef8..4010e511e75ade 100644 --- a/Lib/test/test_ctypes/test_returnfuncptrs.py +++ b/Lib/test/test_ctypes/test_returnfuncptrs.py @@ -1,10 +1,9 @@ +import _ctypes_test import unittest from ctypes import CDLL, CFUNCTYPE, ArgumentError, c_char_p, c_void_p, c_char -import _ctypes_test class ReturnFuncPtrTestCase(unittest.TestCase): - def test_with_prototype(self): # The _ctypes_test shared lib/dll exports quite some functions for testing. # The get_strchr function returns a *pointer* to the C strchr function. diff --git a/Lib/test/test_ctypes/test_slicing.py b/Lib/test/test_ctypes/test_slicing.py index 30db90cd7c0f5e..a592d911cbe6ca 100644 --- a/Lib/test/test_ctypes/test_slicing.py +++ b/Lib/test/test_ctypes/test_slicing.py @@ -1,8 +1,8 @@ +import _ctypes_test import unittest from ctypes import (CDLL, POINTER, sizeof, c_byte, c_short, c_int, c_long, c_char, c_wchar, c_char_p) -import _ctypes_test class SlicesTestCase(unittest.TestCase): def test_getslice_cint(self): @@ -164,7 +164,6 @@ def test_wchar_ptr(self): self.assertEqual(res[len(s)-2:5:-7], tmpl[:5:-7]) dll.my_free(res) -################################################################ if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_stringptr.py b/Lib/test/test_ctypes/test_stringptr.py index 8bf04339d44b39..67c61c6c3e17e6 100644 --- a/Lib/test/test_ctypes/test_stringptr.py +++ b/Lib/test/test_ctypes/test_stringptr.py @@ -1,14 +1,15 @@ -import unittest +import _ctypes_test import sys +import unittest from test import support -from ctypes import CDLL, Structure, POINTER, c_buffer, c_char, c_char_p +from ctypes import (CDLL, Structure, POINTER, create_string_buffer, + c_char, c_char_p) -import _ctypes_test lib = CDLL(_ctypes_test.__file__) -class StringPtrTestCase(unittest.TestCase): +class StringPtrTestCase(unittest.TestCase): @support.refcount_test def test__POINTER_c_char(self): class X(Structure): @@ -17,13 +18,13 @@ class X(Structure): # NULL pointer access self.assertRaises(ValueError, getattr, x.str, "contents") - b = c_buffer(b"Hello, World") + b = create_string_buffer(b"Hello, World") self.assertEqual(sys.getrefcount(b), 2) x.str = b self.assertEqual(sys.getrefcount(b), 3) # POINTER(c_char) and Python string is NOT compatible - # POINTER(c_char) and c_buffer() is compatible + # POINTER(c_char) and create_string_buffer() is compatible for i in range(len(b)): self.assertEqual(b[i], x.str[i]) @@ -35,11 +36,11 @@ class X(Structure): x = X() # c_char_p and Python string is compatible - # c_char_p and c_buffer is NOT compatible + # c_char_p and create_string_buffer is NOT compatible self.assertEqual(x.str, None) x.str = b"Hello, World" self.assertEqual(x.str, b"Hello, World") - b = c_buffer(b"Hello, World") + b = create_string_buffer(b"Hello, World") self.assertRaises(TypeError, setattr, x, b"str", b) @@ -48,15 +49,16 @@ def test_functions(self): strchr.restype = c_char_p # c_char_p and Python string is compatible - # c_char_p and c_buffer are now compatible + # c_char_p and create_string_buffer are now compatible strchr.argtypes = c_char_p, c_char self.assertEqual(strchr(b"abcdef", b"c"), b"cdef") - self.assertEqual(strchr(c_buffer(b"abcdef"), b"c"), b"cdef") + self.assertEqual(strchr(create_string_buffer(b"abcdef"), b"c"), + b"cdef") # POINTER(c_char) and Python string is NOT compatible - # POINTER(c_char) and c_buffer() is compatible + # POINTER(c_char) and create_string_buffer() is compatible strchr.argtypes = POINTER(c_char), c_char - buf = c_buffer(b"abcdef") + buf = create_string_buffer(b"abcdef") self.assertEqual(strchr(buf, b"c"), b"cdef") self.assertEqual(strchr(b"abcdef", b"c"), b"cdef") @@ -65,7 +67,7 @@ def test_functions(self): # So we must keep a reference to buf separately strchr.restype = POINTER(c_char) - buf = c_buffer(b"abcdef") + buf = create_string_buffer(b"abcdef") r = strchr(buf, b"c") x = r[0], r[1], r[2], r[3], r[4] self.assertEqual(x, (b"c", b"d", b"e", b"f", b"\000")) @@ -73,5 +75,6 @@ def test_functions(self): # Because r is a pointer to memory that is freed after deleting buf, # the pointer is hanging and using it would reference freed memory. + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_strings.py b/Lib/test/test_ctypes/test_strings.py index f02d6077def1d8..26f036adfb7585 100644 --- a/Lib/test/test_ctypes/test_strings.py +++ b/Lib/test/test_ctypes/test_strings.py @@ -1,5 +1,6 @@ import unittest -from ctypes import c_buffer, sizeof, byref, c_char, c_wchar +from ctypes import create_string_buffer, sizeof, byref, c_char, c_wchar + class StringArrayTestCase(unittest.TestCase): def test(self): @@ -24,8 +25,8 @@ def test(self): self.assertRaises(ValueError, setattr, buf, "value", b"aaaaaaaa") self.assertRaises(TypeError, setattr, buf, "value", 42) - def test_c_buffer_value(self): - buf = c_buffer(32) + def test_create_string_buffer_value(self): + buf = create_string_buffer(32) buf.value = b"Hello, World" self.assertEqual(buf.value, b"Hello, World") @@ -34,8 +35,8 @@ def test_c_buffer_value(self): self.assertRaises(TypeError, setattr, buf, "value", memoryview(b"abc")) self.assertRaises(ValueError, setattr, buf, "raw", memoryview(b"x" * 100)) - def test_c_buffer_raw(self): - buf = c_buffer(32) + def test_create_string_buffer_raw(self): + buf = create_string_buffer(32) buf.raw = memoryview(b"Hello, World") self.assertEqual(buf.value, b"Hello, World") @@ -90,7 +91,6 @@ def test_wchar(self): repr(byref(c_wchar("x"))) c_wchar("x") - @unittest.skip('test disabled') def test_basic_wstrings(self): cs = c_wstring("abcdef") diff --git a/Lib/test/test_ctypes/test_struct_fields.py b/Lib/test/test_ctypes/test_struct_fields.py index 17a2e69f76d94d..f60dfe5b42ef65 100644 --- a/Lib/test/test_ctypes/test_struct_fields.py +++ b/Lib/test/test_ctypes/test_struct_fields.py @@ -1,6 +1,7 @@ import unittest from ctypes import Structure, Union, sizeof, c_char, c_int + class StructFieldsTestCase(unittest.TestCase): # Structure/Union classes must get 'finalized' sooner or # later, when one of these things happen: @@ -93,5 +94,6 @@ class MyCUnion(Union): self.assertRaises(TypeError, MyCUnion.field.__get__, 'wrong type self', 42) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 98099e8b8c087c..e656d18934779f 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -1,4 +1,6 @@ +import _ctypes_test import platform +import struct import sys import unittest from ctypes import (CDLL, Structure, Union, POINTER, sizeof, byref, alignment, @@ -7,14 +9,15 @@ c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double) from struct import calcsize -import _ctypes_test from test import support + # The following definition is meant to be used from time to time to assist # temporarily disabling tests on specific architectures while investigations # are in progress, to keep buildbots happy. MACHINE = platform.machine() + class SubclassesTest(unittest.TestCase): def test_subclass(self): class X(Structure): @@ -54,6 +57,7 @@ class Z(X): self.assertEqual(Y._fields_, [("b", c_int)]) self.assertEqual(Z._fields_, [("a", c_int)]) + class StructureTestCase(unittest.TestCase): formats = {"c": c_char, "b": c_byte, @@ -187,7 +191,6 @@ class X(Structure): self.assertEqual(sizeof(X), 10) self.assertEqual(X.b.offset, 2) - import struct longlong_size = struct.calcsize("q") longlong_align = struct.calcsize("bq") - longlong_size @@ -740,6 +743,7 @@ class Test8(Union): self.assertEqual(ctx.exception.args[0], 'item 1 in _argtypes_ passes ' 'a union by value, which is unsupported.') + class PointerMemberTestCase(unittest.TestCase): def test(self): @@ -781,6 +785,7 @@ class S(Structure): s.p = None self.assertEqual(s.x, 12345678) + class TestRecursiveStructure(unittest.TestCase): def test_contains_itself(self): class Recursive(Structure): @@ -810,5 +815,6 @@ class Second(Structure): else: self.fail("AttributeError not raised") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_unaligned_structures.py b/Lib/test/test_ctypes/test_unaligned_structures.py index a7e1796d4d63f9..58a00597ef5cc4 100644 --- a/Lib/test/test_ctypes/test_unaligned_structures.py +++ b/Lib/test/test_ctypes/test_unaligned_structures.py @@ -4,6 +4,7 @@ c_float, c_double, c_ushort, c_uint, c_ulong, c_ulonglong) + structures = [] byteswapped_structures = [] @@ -27,6 +28,7 @@ class Y(SwappedStructure): structures.append(X) byteswapped_structures.append(Y) + class TestStructures(unittest.TestCase): def test_native(self): for typ in structures: @@ -42,5 +44,6 @@ def test_swapped(self): o.value = 4 self.assertEqual(o.value, 4) + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_unicode.py b/Lib/test/test_ctypes/test_unicode.py index fe8a157f3c60a7..2ddc7c56544e35 100644 --- a/Lib/test/test_ctypes/test_unicode.py +++ b/Lib/test/test_ctypes/test_unicode.py @@ -1,7 +1,7 @@ -import unittest +import _ctypes_test import ctypes +import unittest -import _ctypes_test class UnicodeTestCase(unittest.TestCase): def test_wcslen(self): diff --git a/Lib/test/test_ctypes/test_values.py b/Lib/test/test_ctypes/test_values.py index 9707e032dc37cc..9f8b69409cb880 100644 --- a/Lib/test/test_ctypes/test_values.py +++ b/Lib/test/test_ctypes/test_values.py @@ -2,14 +2,16 @@ A testcase which accesses *values* in a dll. """ +import _ctypes_test import _imp import importlib.util -import unittest import sys -from ctypes import Structure, CDLL, POINTER, pythonapi, c_ubyte, c_char_p, c_int +import unittest +from ctypes import (Structure, CDLL, POINTER, pythonapi, + _pointer_type_cache, + c_ubyte, c_char_p, c_int) from test.support import import_helper -import _ctypes_test class ValuesTestCase(unittest.TestCase): @@ -31,6 +33,7 @@ def test_undefined(self): ctdll = CDLL(_ctypes_test.__file__) self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol") + class PythonValuesTestCase(unittest.TestCase): """This test only works when python itself is a dll/shared library""" @@ -92,12 +95,12 @@ class struct_frozen(Structure): "_PyImport_FrozenBootstrap example " "in Doc/library/ctypes.rst may be out of date") - from ctypes import _pointer_type_cache del _pointer_type_cache[struct_frozen] def test_undefined(self): self.assertRaises(ValueError, c_int.in_dll, pythonapi, "Undefined_Symbol") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_ctypes/test_varsize_struct.py b/Lib/test/test_ctypes/test_varsize_struct.py index d2fa0b36c785e6..3e6ba6fed07e74 100644 --- a/Lib/test/test_ctypes/test_varsize_struct.py +++ b/Lib/test/test_ctypes/test_varsize_struct.py @@ -1,5 +1,6 @@ -from ctypes import Structure, sizeof, resize, c_int import unittest +from ctypes import Structure, sizeof, resize, c_int + class VarSizeTest(unittest.TestCase): def test_resize(self): @@ -46,5 +47,6 @@ def test_zerosized_array(self): self.assertRaises(IndexError, array.__setitem__, -1, None) self.assertRaises(IndexError, array.__getitem__, -1) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_ctypes/test_win32.py b/Lib/test/test_ctypes/test_win32.py index a8987dd1da6896..01e624f76f0685 100644 --- a/Lib/test/test_ctypes/test_win32.py +++ b/Lib/test/test_ctypes/test_win32.py @@ -2,9 +2,11 @@ import _ctypes_test import ctypes +import errno import sys import unittest from ctypes import (CDLL, Structure, POINTER, pointer, sizeof, byref, + _pointer_type_cache, c_void_p, c_char, c_int, c_long) from test import support @@ -47,7 +49,6 @@ class S(Structure): self.assertEqual(value, expected) - @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') class TestWintypes(unittest.TestCase): def test_HWND(self): @@ -72,11 +73,11 @@ def test_COMError(self): self.assertEqual(ex.text, "text") self.assertEqual(ex.details, ("details",)) + @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') class TestWinError(unittest.TestCase): def test_winerror(self): # see Issue 16169 - import errno ERROR_INVALID_PARAMETER = 87 msg = ctypes.FormatError(ERROR_INVALID_PARAMETER).strip() args = (errno.EINVAL, msg, None, ERROR_INVALID_PARAMETER) @@ -136,7 +137,6 @@ class RECT(Structure): self.assertEqual(ret.bottom, bottom.value) # to not leak references, we must clean _pointer_type_cache - from ctypes import _pointer_type_cache del _pointer_type_cache[RECT] diff --git a/Lib/test/test_ctypes/test_wintypes.py b/Lib/test/test_ctypes/test_wintypes.py index 66fb8b78545a60..a04d725a47395e 100644 --- a/Lib/test/test_ctypes/test_wintypes.py +++ b/Lib/test/test_ctypes/test_wintypes.py @@ -1,10 +1,9 @@ # See # for reference. +# +# Tests also work on POSIX import unittest - -# also work on POSIX - from ctypes import POINTER, cast, c_int16 from ctypes import wintypes From 12b6d844d8819955508bd86db106f17516be3f77 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 15 Jun 2023 01:08:12 +0100 Subject: [PATCH 054/446] gh-105800: Issue SyntaxWarning in f-strings for invalid escape sequences (#105801) --- Lib/test/test_fstring.py | 3 +++ .../2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst | 2 ++ Parser/action_helpers.c | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 031b94d8d58a39..cbb03080f797bc 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -907,6 +907,9 @@ def test_backslashes_in_string_part(self): with self.assertWarns(DeprecationWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') + with self.assertWarns(SyntaxWarning): # invalid escape sequence + value = eval(r"f'\g'") + self.assertEqual(value, '\\g') self.assertEqual(f'\\{6*7}', '\\42') self.assertEqual(fr'\{6*7}', '\\42') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst new file mode 100644 index 00000000000000..d6ef7b68b833c6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-14-22-52-06.gh-issue-105800.hdpPzZ.rst @@ -0,0 +1,2 @@ +Correctly issue :exc:`SyntaxWarning` in f-strings if invalid sequences are +used. Patch by Pablo Galindo diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 7786124fde82d0..70c267bb212fcb 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -1225,7 +1225,7 @@ _PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq // Fstring stuff static expr_ty -_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) { +_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant, Token* token) { assert(PyUnicode_CheckExact(constant->v.Constant.value)); const char* bstr = PyUnicode_AsUTF8(constant->v.Constant.value); @@ -1241,7 +1241,7 @@ _PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) { } is_raw = is_raw || strchr(bstr, '\\') == NULL; - PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, NULL); + PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, token); if (str == NULL) { _Pypegen_raise_decode_error(p); return NULL; @@ -1315,7 +1315,7 @@ _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b for (Py_ssize_t i = 0; i < n_items; i++) { expr_ty item = asdl_seq_GET(expr, i); if (item->kind == Constant_kind) { - item = _PyPegen_decode_fstring_part(p, is_raw, item); + item = _PyPegen_decode_fstring_part(p, is_raw, item, b); if (item == NULL) { return NULL; } From 10bf2cd404320252ef162d5699cb7ce52a970d44 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Thu, 15 Jun 2023 02:31:30 +0100 Subject: [PATCH 055/446] GH-89812: Churn `pathlib.Path` test methods (#105807) Re-arrange `pathlib.Path` test methods in source code. No other changes. The test methods are arranged in two groups. The first group checks `stat()`, `open()`, `iterdir()`, `readlink()`, and derived methods like `exists()`, `read_text()`, `glob()` and `resolve()`. The second group checks all other `Path` methods. To minimise the diff I've maintained the method order within groups where possible. This patch prepares the ground for a new `_AbstractPath` class, which will support methods in the first group above. By churning the test methods here, subsequent patches will be easier to review and less likely to break things. --- Lib/test/test_pathlib.py | 790 +++++++++++++++++++-------------------- 1 file changed, 395 insertions(+), 395 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 46ac30e91e32aa..02a0f25e0bd991 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1642,101 +1642,6 @@ def assertFileNotFound(self, func, *args, **kwargs): def assertEqualNormCase(self, path_a, path_b): self.assertEqual(os.path.normcase(path_a), os.path.normcase(path_b)) - def test_concrete_class(self): - if self.cls is pathlib.Path: - expected = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath - else: - expected = self.cls - p = self.cls('a') - self.assertIs(type(p), expected) - - def test_unsupported_flavour(self): - if self.cls._flavour is os.path: - self.skipTest("path flavour is supported") - else: - self.assertRaises(NotImplementedError, self.cls) - - def _test_cwd(self, p): - q = self.cls(os.getcwd()) - self.assertEqual(p, q) - self.assertEqualNormCase(str(p), str(q)) - self.assertIs(type(p), type(q)) - self.assertTrue(p.is_absolute()) - - def test_cwd(self): - p = self.cls.cwd() - self._test_cwd(p) - - def test_absolute_common(self): - P = self.cls - - with mock.patch("os.getcwd") as getcwd: - getcwd.return_value = BASE - - # Simple relative paths. - self.assertEqual(str(P().absolute()), BASE) - self.assertEqual(str(P('.').absolute()), BASE) - self.assertEqual(str(P('a').absolute()), os.path.join(BASE, 'a')) - self.assertEqual(str(P('a', 'b', 'c').absolute()), os.path.join(BASE, 'a', 'b', 'c')) - - # Symlinks should not be resolved. - self.assertEqual(str(P('linkB', 'fileB').absolute()), os.path.join(BASE, 'linkB', 'fileB')) - self.assertEqual(str(P('brokenLink').absolute()), os.path.join(BASE, 'brokenLink')) - self.assertEqual(str(P('brokenLinkLoop').absolute()), os.path.join(BASE, 'brokenLinkLoop')) - - # '..' entries should be preserved and not normalised. - self.assertEqual(str(P('..').absolute()), os.path.join(BASE, '..')) - self.assertEqual(str(P('a', '..').absolute()), os.path.join(BASE, 'a', '..')) - self.assertEqual(str(P('..', 'b').absolute()), os.path.join(BASE, '..', 'b')) - - def _test_home(self, p): - q = self.cls(os.path.expanduser('~')) - self.assertEqual(p, q) - self.assertEqualNormCase(str(p), str(q)) - self.assertIs(type(p), type(q)) - self.assertTrue(p.is_absolute()) - - @unittest.skipIf( - pwd is None, reason="Test requires pwd module to get homedir." - ) - def test_home(self): - with os_helper.EnvironmentVarGuard() as env: - self._test_home(self.cls.home()) - - env.clear() - env['USERPROFILE'] = os.path.join(BASE, 'userprofile') - self._test_home(self.cls.home()) - - # bpo-38883: ignore `HOME` when set on windows - env['HOME'] = os.path.join(BASE, 'home') - self._test_home(self.cls.home()) - - def test_with_segments(self): - class P(self.cls): - def __init__(self, *pathsegments, session_id): - super().__init__(*pathsegments) - self.session_id = session_id - - def with_segments(self, *pathsegments): - return type(self)(*pathsegments, session_id=self.session_id) - p = P(BASE, session_id=42) - self.assertEqual(42, p.absolute().session_id) - self.assertEqual(42, p.resolve().session_id) - if not is_wasi: # WASI has no user accounts. - self.assertEqual(42, p.with_segments('~').expanduser().session_id) - self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id) - self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id) - if os_helper.can_symlink(): - self.assertEqual(42, (p / 'linkA').readlink().session_id) - for path in p.iterdir(): - self.assertEqual(42, path.session_id) - for path in p.glob('*'): - self.assertEqual(42, path.session_id) - for path in p.rglob('*'): - self.assertEqual(42, path.session_id) - for dirpath, dirnames, filenames in p.walk(): - self.assertEqual(42, dirpath.session_id) - def test_samefile(self): fileA_path = os.path.join(BASE, 'fileA') fileB_path = os.path.join(BASE, 'dirB', 'fileB') @@ -1762,22 +1667,6 @@ def test_empty_path(self): p = self.cls('') self.assertEqual(p.stat(), os.stat('.')) - @unittest.skipIf(is_wasi, "WASI has no user accounts.") - def test_expanduser_common(self): - P = self.cls - p = P('~') - self.assertEqual(p.expanduser(), P(os.path.expanduser('~'))) - p = P('foo') - self.assertEqual(p.expanduser(), p) - p = P('/~') - self.assertEqual(p.expanduser(), p) - p = P('../~') - self.assertEqual(p.expanduser(), p) - p = P(P('').absolute().anchor) / '~' - self.assertEqual(p.expanduser(), p) - p = P('~/a:b') - self.assertEqual(p.expanduser(), P(os.path.expanduser('~'), './a:b')) - def test_exists(self): P = self.cls p = P(BASE) @@ -2156,6 +2045,16 @@ def test_glob_above_recursion_limit(self): with set_recursion_limit(recursion_limit): list(base.glob('**')) + @os_helper.skip_unless_symlink + def test_readlink(self): + P = self.cls(BASE) + self.assertEqual((P / 'linkA').readlink(), self.cls('fileA')) + self.assertEqual((P / 'brokenLink').readlink(), + self.cls('non-existing')) + self.assertEqual((P / 'linkB').readlink(), self.cls('dirB')) + with self.assertRaises(OSError): + (P / 'fileA').readlink() + def _check_resolve(self, p, expected, strict=True): q = p.resolve(strict) self.assertEqual(q, expected) @@ -2238,47 +2137,6 @@ def test_resolve_dot(self): # Non-strict self.assertEqual(r.resolve(strict=False), p / '3' / '4') - def test_resolve_nonexist_relative_issue38671(self): - p = self.cls('non', 'exist') - - old_cwd = os.getcwd() - os.chdir(BASE) - try: - self.assertEqual(p.resolve(), self.cls(BASE, p)) - finally: - os.chdir(old_cwd) - - @os_helper.skip_unless_working_chmod - def test_chmod(self): - p = self.cls(BASE) / 'fileA' - mode = p.stat().st_mode - # Clear writable bit. - new_mode = mode & ~0o222 - p.chmod(new_mode) - self.assertEqual(p.stat().st_mode, new_mode) - # Set writable bit. - new_mode = mode | 0o222 - p.chmod(new_mode) - self.assertEqual(p.stat().st_mode, new_mode) - - # On Windows, os.chmod does not follow symlinks (issue #15411) - @only_posix - @os_helper.skip_unless_working_chmod - def test_chmod_follow_symlinks_true(self): - p = self.cls(BASE) / 'linkA' - q = p.resolve() - mode = q.stat().st_mode - # Clear writable bit. - new_mode = mode & ~0o222 - p.chmod(new_mode, follow_symlinks=True) - self.assertEqual(q.stat().st_mode, new_mode) - # Set writable bit - new_mode = mode | 0o222 - p.chmod(new_mode, follow_symlinks=True) - self.assertEqual(q.stat().st_mode, new_mode) - - # XXX also need a test for lchmod. - @os_helper.skip_unless_working_chmod def test_stat(self): p = self.cls(BASE) / 'fileA' @@ -2311,82 +2169,396 @@ def test_lstat_nosymlink(self): st = p.stat() self.assertEqual(st, p.lstat()) - @unittest.skipUnless(pwd, "the pwd module is needed for this test") - def test_owner(self): - p = self.cls(BASE) / 'fileA' - uid = p.stat().st_uid - try: - name = pwd.getpwuid(uid).pw_name - except KeyError: - self.skipTest( - "user %d doesn't have an entry in the system database" % uid) - self.assertEqual(name, p.owner()) - - @unittest.skipUnless(grp, "the grp module is needed for this test") - def test_group(self): - p = self.cls(BASE) / 'fileA' - gid = p.stat().st_gid - try: - name = grp.getgrgid(gid).gr_name - except KeyError: - self.skipTest( - "group %d doesn't have an entry in the system database" % gid) - self.assertEqual(name, p.group()) - - def test_unlink(self): - p = self.cls(BASE) / 'fileA' - p.unlink() - self.assertFileNotFound(p.stat) - self.assertFileNotFound(p.unlink) - - def test_unlink_missing_ok(self): - p = self.cls(BASE) / 'fileAAA' - self.assertFileNotFound(p.unlink) - p.unlink(missing_ok=True) - - def test_rmdir(self): - p = self.cls(BASE) / 'dirA' - for q in p.iterdir(): - q.unlink() - p.rmdir() - self.assertFileNotFound(p.stat) - self.assertFileNotFound(p.unlink) - - @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present") - def test_hardlink_to(self): + def test_is_dir(self): P = self.cls(BASE) - target = P / 'fileA' - size = target.stat().st_size - # linking to another path. - link = P / 'dirA' / 'fileAA' - link.hardlink_to(target) - self.assertEqual(link.stat().st_size, size) - self.assertTrue(os.path.samefile(target, link)) - self.assertTrue(target.exists()) - # Linking to a str of a relative path. - link2 = P / 'dirA' / 'fileAAA' - target2 = rel_join('fileA') - link2.hardlink_to(target2) - self.assertEqual(os.stat(target2).st_size, size) - self.assertTrue(link2.exists()) + self.assertTrue((P / 'dirA').is_dir()) + self.assertFalse((P / 'fileA').is_dir()) + self.assertFalse((P / 'non-existing').is_dir()) + self.assertFalse((P / 'fileA' / 'bah').is_dir()) + if os_helper.can_symlink(): + self.assertFalse((P / 'linkA').is_dir()) + self.assertTrue((P / 'linkB').is_dir()) + self.assertFalse((P/ 'brokenLink').is_dir(), False) + self.assertIs((P / 'dirA\udfff').is_dir(), False) + self.assertIs((P / 'dirA\x00').is_dir(), False) - @unittest.skipIf(hasattr(os, "link"), "os.link() is present") - def test_link_to_not_implemented(self): + def test_is_file(self): P = self.cls(BASE) - p = P / 'fileA' - # linking to another path. - q = P / 'dirA' / 'fileAA' - with self.assertRaises(NotImplementedError): - q.hardlink_to(p) + self.assertTrue((P / 'fileA').is_file()) + self.assertFalse((P / 'dirA').is_file()) + self.assertFalse((P / 'non-existing').is_file()) + self.assertFalse((P / 'fileA' / 'bah').is_file()) + if os_helper.can_symlink(): + self.assertTrue((P / 'linkA').is_file()) + self.assertFalse((P / 'linkB').is_file()) + self.assertFalse((P/ 'brokenLink').is_file()) + self.assertIs((P / 'fileA\udfff').is_file(), False) + self.assertIs((P / 'fileA\x00').is_file(), False) - def test_rename(self): + def test_is_mount(self): P = self.cls(BASE) - p = P / 'fileA' - size = p.stat().st_size - # Renaming to another path. - q = P / 'dirA' / 'fileAA' - renamed_p = p.rename(q) - self.assertEqual(renamed_p, q) + if os.name == 'nt': + R = self.cls('c:\\') + else: + R = self.cls('/') + self.assertFalse((P / 'fileA').is_mount()) + self.assertFalse((P / 'dirA').is_mount()) + self.assertFalse((P / 'non-existing').is_mount()) + self.assertFalse((P / 'fileA' / 'bah').is_mount()) + self.assertTrue(R.is_mount()) + if os_helper.can_symlink(): + self.assertFalse((P / 'linkA').is_mount()) + self.assertIs((R / '\udfff').is_mount(), False) + + def test_is_symlink(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_symlink()) + self.assertFalse((P / 'dirA').is_symlink()) + self.assertFalse((P / 'non-existing').is_symlink()) + self.assertFalse((P / 'fileA' / 'bah').is_symlink()) + if os_helper.can_symlink(): + self.assertTrue((P / 'linkA').is_symlink()) + self.assertTrue((P / 'linkB').is_symlink()) + self.assertTrue((P/ 'brokenLink').is_symlink()) + self.assertIs((P / 'fileA\udfff').is_file(), False) + self.assertIs((P / 'fileA\x00').is_file(), False) + if os_helper.can_symlink(): + self.assertIs((P / 'linkA\udfff').is_file(), False) + self.assertIs((P / 'linkA\x00').is_file(), False) + + def test_is_fifo_false(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_fifo()) + self.assertFalse((P / 'dirA').is_fifo()) + self.assertFalse((P / 'non-existing').is_fifo()) + self.assertFalse((P / 'fileA' / 'bah').is_fifo()) + self.assertIs((P / 'fileA\udfff').is_fifo(), False) + self.assertIs((P / 'fileA\x00').is_fifo(), False) + + def test_is_socket_false(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_socket()) + self.assertFalse((P / 'dirA').is_socket()) + self.assertFalse((P / 'non-existing').is_socket()) + self.assertFalse((P / 'fileA' / 'bah').is_socket()) + self.assertIs((P / 'fileA\udfff').is_socket(), False) + self.assertIs((P / 'fileA\x00').is_socket(), False) + + def test_is_block_device_false(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_block_device()) + self.assertFalse((P / 'dirA').is_block_device()) + self.assertFalse((P / 'non-existing').is_block_device()) + self.assertFalse((P / 'fileA' / 'bah').is_block_device()) + self.assertIs((P / 'fileA\udfff').is_block_device(), False) + self.assertIs((P / 'fileA\x00').is_block_device(), False) + + def test_is_char_device_false(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_char_device()) + self.assertFalse((P / 'dirA').is_char_device()) + self.assertFalse((P / 'non-existing').is_char_device()) + self.assertFalse((P / 'fileA' / 'bah').is_char_device()) + self.assertIs((P / 'fileA\udfff').is_char_device(), False) + self.assertIs((P / 'fileA\x00').is_char_device(), False) + + def test_pickling_common(self): + p = self.cls(BASE, 'fileA') + for proto in range(0, pickle.HIGHEST_PROTOCOL + 1): + dumped = pickle.dumps(p, proto) + pp = pickle.loads(dumped) + self.assertEqual(pp.stat(), p.stat()) + + def test_parts_interning(self): + P = self.cls + p = P('/usr/bin/foo') + q = P('/usr/local/bin') + # 'usr' + self.assertIs(p.parts[1], q.parts[1]) + # 'bin' + self.assertIs(p.parts[2], q.parts[3]) + + def _check_complex_symlinks(self, link0_target): + # Test solving a non-looping chain of symlinks (issue #19887). + P = self.cls(BASE) + self.dirlink(os.path.join('link0', 'link0'), join('link1')) + self.dirlink(os.path.join('link1', 'link1'), join('link2')) + self.dirlink(os.path.join('link2', 'link2'), join('link3')) + self.dirlink(link0_target, join('link0')) + + # Resolve absolute paths. + p = (P / 'link0').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = (P / 'link1').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = (P / 'link2').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = (P / 'link3').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + + # Resolve relative paths. + old_path = os.getcwd() + os.chdir(BASE) + try: + p = self.cls('link0').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = self.cls('link1').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = self.cls('link2').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + p = self.cls('link3').resolve() + self.assertEqual(p, P) + self.assertEqualNormCase(str(p), BASE) + finally: + os.chdir(old_path) + + @os_helper.skip_unless_symlink + def test_complex_symlinks_absolute(self): + self._check_complex_symlinks(BASE) + + @os_helper.skip_unless_symlink + def test_complex_symlinks_relative(self): + self._check_complex_symlinks('.') + + @os_helper.skip_unless_symlink + def test_complex_symlinks_relative_dot_dot(self): + self._check_complex_symlinks(os.path.join('dirA', '..')) + + def test_concrete_class(self): + if self.cls is pathlib.Path: + expected = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath + else: + expected = self.cls + p = self.cls('a') + self.assertIs(type(p), expected) + + def test_unsupported_flavour(self): + if self.cls._flavour is os.path: + self.skipTest("path flavour is supported") + else: + self.assertRaises(NotImplementedError, self.cls) + + def _test_cwd(self, p): + q = self.cls(os.getcwd()) + self.assertEqual(p, q) + self.assertEqualNormCase(str(p), str(q)) + self.assertIs(type(p), type(q)) + self.assertTrue(p.is_absolute()) + + def test_cwd(self): + p = self.cls.cwd() + self._test_cwd(p) + + def test_absolute_common(self): + P = self.cls + + with mock.patch("os.getcwd") as getcwd: + getcwd.return_value = BASE + + # Simple relative paths. + self.assertEqual(str(P().absolute()), BASE) + self.assertEqual(str(P('.').absolute()), BASE) + self.assertEqual(str(P('a').absolute()), os.path.join(BASE, 'a')) + self.assertEqual(str(P('a', 'b', 'c').absolute()), os.path.join(BASE, 'a', 'b', 'c')) + + # Symlinks should not be resolved. + self.assertEqual(str(P('linkB', 'fileB').absolute()), os.path.join(BASE, 'linkB', 'fileB')) + self.assertEqual(str(P('brokenLink').absolute()), os.path.join(BASE, 'brokenLink')) + self.assertEqual(str(P('brokenLinkLoop').absolute()), os.path.join(BASE, 'brokenLinkLoop')) + + # '..' entries should be preserved and not normalised. + self.assertEqual(str(P('..').absolute()), os.path.join(BASE, '..')) + self.assertEqual(str(P('a', '..').absolute()), os.path.join(BASE, 'a', '..')) + self.assertEqual(str(P('..', 'b').absolute()), os.path.join(BASE, '..', 'b')) + + def _test_home(self, p): + q = self.cls(os.path.expanduser('~')) + self.assertEqual(p, q) + self.assertEqualNormCase(str(p), str(q)) + self.assertIs(type(p), type(q)) + self.assertTrue(p.is_absolute()) + + @unittest.skipIf( + pwd is None, reason="Test requires pwd module to get homedir." + ) + def test_home(self): + with os_helper.EnvironmentVarGuard() as env: + self._test_home(self.cls.home()) + + env.clear() + env['USERPROFILE'] = os.path.join(BASE, 'userprofile') + self._test_home(self.cls.home()) + + # bpo-38883: ignore `HOME` when set on windows + env['HOME'] = os.path.join(BASE, 'home') + self._test_home(self.cls.home()) + + @unittest.skipIf(is_wasi, "WASI has no user accounts.") + def test_expanduser_common(self): + P = self.cls + p = P('~') + self.assertEqual(p.expanduser(), P(os.path.expanduser('~'))) + p = P('foo') + self.assertEqual(p.expanduser(), p) + p = P('/~') + self.assertEqual(p.expanduser(), p) + p = P('../~') + self.assertEqual(p.expanduser(), p) + p = P(P('').absolute().anchor) / '~' + self.assertEqual(p.expanduser(), p) + p = P('~/a:b') + self.assertEqual(p.expanduser(), P(os.path.expanduser('~'), './a:b')) + + def test_with_segments(self): + class P(self.cls): + def __init__(self, *pathsegments, session_id): + super().__init__(*pathsegments) + self.session_id = session_id + + def with_segments(self, *pathsegments): + return type(self)(*pathsegments, session_id=self.session_id) + p = P(BASE, session_id=42) + self.assertEqual(42, p.absolute().session_id) + self.assertEqual(42, p.resolve().session_id) + if not is_wasi: # WASI has no user accounts. + self.assertEqual(42, p.with_segments('~').expanduser().session_id) + self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id) + self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id) + if os_helper.can_symlink(): + self.assertEqual(42, (p / 'linkA').readlink().session_id) + for path in p.iterdir(): + self.assertEqual(42, path.session_id) + for path in p.glob('*'): + self.assertEqual(42, path.session_id) + for path in p.rglob('*'): + self.assertEqual(42, path.session_id) + for dirpath, dirnames, filenames in p.walk(): + self.assertEqual(42, dirpath.session_id) + + def test_resolve_nonexist_relative_issue38671(self): + p = self.cls('non', 'exist') + + old_cwd = os.getcwd() + os.chdir(BASE) + try: + self.assertEqual(p.resolve(), self.cls(BASE, p)) + finally: + os.chdir(old_cwd) + + @os_helper.skip_unless_working_chmod + def test_chmod(self): + p = self.cls(BASE) / 'fileA' + mode = p.stat().st_mode + # Clear writable bit. + new_mode = mode & ~0o222 + p.chmod(new_mode) + self.assertEqual(p.stat().st_mode, new_mode) + # Set writable bit. + new_mode = mode | 0o222 + p.chmod(new_mode) + self.assertEqual(p.stat().st_mode, new_mode) + + # On Windows, os.chmod does not follow symlinks (issue #15411) + @only_posix + @os_helper.skip_unless_working_chmod + def test_chmod_follow_symlinks_true(self): + p = self.cls(BASE) / 'linkA' + q = p.resolve() + mode = q.stat().st_mode + # Clear writable bit. + new_mode = mode & ~0o222 + p.chmod(new_mode, follow_symlinks=True) + self.assertEqual(q.stat().st_mode, new_mode) + # Set writable bit + new_mode = mode | 0o222 + p.chmod(new_mode, follow_symlinks=True) + self.assertEqual(q.stat().st_mode, new_mode) + + # XXX also need a test for lchmod. + + @unittest.skipUnless(pwd, "the pwd module is needed for this test") + def test_owner(self): + p = self.cls(BASE) / 'fileA' + uid = p.stat().st_uid + try: + name = pwd.getpwuid(uid).pw_name + except KeyError: + self.skipTest( + "user %d doesn't have an entry in the system database" % uid) + self.assertEqual(name, p.owner()) + + @unittest.skipUnless(grp, "the grp module is needed for this test") + def test_group(self): + p = self.cls(BASE) / 'fileA' + gid = p.stat().st_gid + try: + name = grp.getgrgid(gid).gr_name + except KeyError: + self.skipTest( + "group %d doesn't have an entry in the system database" % gid) + self.assertEqual(name, p.group()) + + def test_unlink(self): + p = self.cls(BASE) / 'fileA' + p.unlink() + self.assertFileNotFound(p.stat) + self.assertFileNotFound(p.unlink) + + def test_unlink_missing_ok(self): + p = self.cls(BASE) / 'fileAAA' + self.assertFileNotFound(p.unlink) + p.unlink(missing_ok=True) + + def test_rmdir(self): + p = self.cls(BASE) / 'dirA' + for q in p.iterdir(): + q.unlink() + p.rmdir() + self.assertFileNotFound(p.stat) + self.assertFileNotFound(p.unlink) + + @unittest.skipUnless(hasattr(os, "link"), "os.link() is not present") + def test_hardlink_to(self): + P = self.cls(BASE) + target = P / 'fileA' + size = target.stat().st_size + # linking to another path. + link = P / 'dirA' / 'fileAA' + link.hardlink_to(target) + self.assertEqual(link.stat().st_size, size) + self.assertTrue(os.path.samefile(target, link)) + self.assertTrue(target.exists()) + # Linking to a str of a relative path. + link2 = P / 'dirA' / 'fileAAA' + target2 = rel_join('fileA') + link2.hardlink_to(target2) + self.assertEqual(os.stat(target2).st_size, size) + self.assertTrue(link2.exists()) + + @unittest.skipIf(hasattr(os, "link"), "os.link() is present") + def test_link_to_not_implemented(self): + P = self.cls(BASE) + p = P / 'fileA' + # linking to another path. + q = P / 'dirA' / 'fileAA' + with self.assertRaises(NotImplementedError): + q.hardlink_to(p) + + def test_rename(self): + P = self.cls(BASE) + p = P / 'fileA' + size = p.stat().st_size + # Renaming to another path. + q = P / 'dirA' / 'fileAA' + renamed_p = p.rename(q) + self.assertEqual(renamed_p, q) self.assertEqual(q.stat().st_size, size) self.assertFileNotFound(p.stat) # Renaming to a str of a relative path. @@ -2413,16 +2585,6 @@ def test_replace(self): self.assertEqual(os.stat(r).st_size, size) self.assertFileNotFound(q.stat) - @os_helper.skip_unless_symlink - def test_readlink(self): - P = self.cls(BASE) - self.assertEqual((P / 'linkA').readlink(), self.cls('fileA')) - self.assertEqual((P / 'brokenLink').readlink(), - self.cls('non-existing')) - self.assertEqual((P / 'linkB').readlink(), self.cls('dirB')) - with self.assertRaises(OSError): - (P / 'fileA').readlink() - def test_touch_common(self): P = self.cls(BASE) p = P / 'newfileA' @@ -2614,63 +2776,6 @@ def test_symlink_to(self): self.assertTrue(link.is_dir()) self.assertTrue(list(link.iterdir())) - def test_is_dir(self): - P = self.cls(BASE) - self.assertTrue((P / 'dirA').is_dir()) - self.assertFalse((P / 'fileA').is_dir()) - self.assertFalse((P / 'non-existing').is_dir()) - self.assertFalse((P / 'fileA' / 'bah').is_dir()) - if os_helper.can_symlink(): - self.assertFalse((P / 'linkA').is_dir()) - self.assertTrue((P / 'linkB').is_dir()) - self.assertFalse((P/ 'brokenLink').is_dir(), False) - self.assertIs((P / 'dirA\udfff').is_dir(), False) - self.assertIs((P / 'dirA\x00').is_dir(), False) - - def test_is_file(self): - P = self.cls(BASE) - self.assertTrue((P / 'fileA').is_file()) - self.assertFalse((P / 'dirA').is_file()) - self.assertFalse((P / 'non-existing').is_file()) - self.assertFalse((P / 'fileA' / 'bah').is_file()) - if os_helper.can_symlink(): - self.assertTrue((P / 'linkA').is_file()) - self.assertFalse((P / 'linkB').is_file()) - self.assertFalse((P/ 'brokenLink').is_file()) - self.assertIs((P / 'fileA\udfff').is_file(), False) - self.assertIs((P / 'fileA\x00').is_file(), False) - - def test_is_mount(self): - P = self.cls(BASE) - if os.name == 'nt': - R = self.cls('c:\\') - else: - R = self.cls('/') - self.assertFalse((P / 'fileA').is_mount()) - self.assertFalse((P / 'dirA').is_mount()) - self.assertFalse((P / 'non-existing').is_mount()) - self.assertFalse((P / 'fileA' / 'bah').is_mount()) - self.assertTrue(R.is_mount()) - if os_helper.can_symlink(): - self.assertFalse((P / 'linkA').is_mount()) - self.assertIs((R / '\udfff').is_mount(), False) - - def test_is_symlink(self): - P = self.cls(BASE) - self.assertFalse((P / 'fileA').is_symlink()) - self.assertFalse((P / 'dirA').is_symlink()) - self.assertFalse((P / 'non-existing').is_symlink()) - self.assertFalse((P / 'fileA' / 'bah').is_symlink()) - if os_helper.can_symlink(): - self.assertTrue((P / 'linkA').is_symlink()) - self.assertTrue((P / 'linkB').is_symlink()) - self.assertTrue((P/ 'brokenLink').is_symlink()) - self.assertIs((P / 'fileA\udfff').is_file(), False) - self.assertIs((P / 'fileA\x00').is_file(), False) - if os_helper.can_symlink(): - self.assertIs((P / 'linkA\udfff').is_file(), False) - self.assertIs((P / 'linkA\x00').is_file(), False) - def test_is_junction(self): P = self.cls(BASE) @@ -2678,15 +2783,6 @@ def test_is_junction(self): self.assertEqual(P.is_junction(), P._flavour.isjunction.return_value) P._flavour.isjunction.assert_called_once_with(P) - def test_is_fifo_false(self): - P = self.cls(BASE) - self.assertFalse((P / 'fileA').is_fifo()) - self.assertFalse((P / 'dirA').is_fifo()) - self.assertFalse((P / 'non-existing').is_fifo()) - self.assertFalse((P / 'fileA' / 'bah').is_fifo()) - self.assertIs((P / 'fileA\udfff').is_fifo(), False) - self.assertIs((P / 'fileA\x00').is_fifo(), False) - @unittest.skipUnless(hasattr(os, "mkfifo"), "os.mkfifo() required") @unittest.skipIf(sys.platform == "vxworks", "fifo requires special path on VxWorks") @@ -2702,15 +2798,6 @@ def test_is_fifo_true(self): self.assertIs(self.cls(BASE, 'myfifo\udfff').is_fifo(), False) self.assertIs(self.cls(BASE, 'myfifo\x00').is_fifo(), False) - def test_is_socket_false(self): - P = self.cls(BASE) - self.assertFalse((P / 'fileA').is_socket()) - self.assertFalse((P / 'dirA').is_socket()) - self.assertFalse((P / 'non-existing').is_socket()) - self.assertFalse((P / 'fileA' / 'bah').is_socket()) - self.assertIs((P / 'fileA\udfff').is_socket(), False) - self.assertIs((P / 'fileA\x00').is_socket(), False) - @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") @unittest.skipIf( is_emscripten, "Unix sockets are not implemented on Emscripten." @@ -2734,24 +2821,6 @@ def test_is_socket_true(self): self.assertIs(self.cls(BASE, 'mysock\udfff').is_socket(), False) self.assertIs(self.cls(BASE, 'mysock\x00').is_socket(), False) - def test_is_block_device_false(self): - P = self.cls(BASE) - self.assertFalse((P / 'fileA').is_block_device()) - self.assertFalse((P / 'dirA').is_block_device()) - self.assertFalse((P / 'non-existing').is_block_device()) - self.assertFalse((P / 'fileA' / 'bah').is_block_device()) - self.assertIs((P / 'fileA\udfff').is_block_device(), False) - self.assertIs((P / 'fileA\x00').is_block_device(), False) - - def test_is_char_device_false(self): - P = self.cls(BASE) - self.assertFalse((P / 'fileA').is_char_device()) - self.assertFalse((P / 'dirA').is_char_device()) - self.assertFalse((P / 'non-existing').is_char_device()) - self.assertFalse((P / 'fileA' / 'bah').is_char_device()) - self.assertIs((P / 'fileA\udfff').is_char_device(), False) - self.assertIs((P / 'fileA\x00').is_char_device(), False) - def test_is_char_device_true(self): # Under Unix, /dev/null should generally be a char device. P = self.cls('/dev/null') @@ -2763,75 +2832,6 @@ def test_is_char_device_true(self): self.assertIs(self.cls('/dev/null\udfff').is_char_device(), False) self.assertIs(self.cls('/dev/null\x00').is_char_device(), False) - def test_pickling_common(self): - p = self.cls(BASE, 'fileA') - for proto in range(0, pickle.HIGHEST_PROTOCOL + 1): - dumped = pickle.dumps(p, proto) - pp = pickle.loads(dumped) - self.assertEqual(pp.stat(), p.stat()) - - def test_parts_interning(self): - P = self.cls - p = P('/usr/bin/foo') - q = P('/usr/local/bin') - # 'usr' - self.assertIs(p.parts[1], q.parts[1]) - # 'bin' - self.assertIs(p.parts[2], q.parts[3]) - - def _check_complex_symlinks(self, link0_target): - # Test solving a non-looping chain of symlinks (issue #19887). - P = self.cls(BASE) - self.dirlink(os.path.join('link0', 'link0'), join('link1')) - self.dirlink(os.path.join('link1', 'link1'), join('link2')) - self.dirlink(os.path.join('link2', 'link2'), join('link3')) - self.dirlink(link0_target, join('link0')) - - # Resolve absolute paths. - p = (P / 'link0').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = (P / 'link1').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = (P / 'link2').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = (P / 'link3').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - - # Resolve relative paths. - old_path = os.getcwd() - os.chdir(BASE) - try: - p = self.cls('link0').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = self.cls('link1').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = self.cls('link2').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - p = self.cls('link3').resolve() - self.assertEqual(p, P) - self.assertEqualNormCase(str(p), BASE) - finally: - os.chdir(old_path) - - @os_helper.skip_unless_symlink - def test_complex_symlinks_absolute(self): - self._check_complex_symlinks(BASE) - - @os_helper.skip_unless_symlink - def test_complex_symlinks_relative(self): - self._check_complex_symlinks('.') - - @os_helper.skip_unless_symlink - def test_complex_symlinks_relative_dot_dot(self): - self._check_complex_symlinks(os.path.join('dirA', '..')) - def test_passing_kwargs_deprecated(self): with self.assertWarns(DeprecationWarning): self.cls(foo="bar") From 006a4532058f1fadba93283c0f45b0d82735b364 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 15 Jun 2023 06:51:42 +0100 Subject: [PATCH 056/446] Improve docs for `typing.dataclass_transform` (#105792) --- Doc/library/typing.rst | 106 +++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 73555d54115f3a..859700e0c69b1d 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2539,16 +2539,19 @@ Functions and decorators .. versionadded:: 3.11 -.. decorator:: dataclass_transform +.. decorator:: dataclass_transform(*, eq_default=True, order_default=False, \ + kw_only_default=False, frozen_default=False, \ + field_specifiers=(), **kwargs) Decorator to mark an object as providing - :func:`~dataclasses.dataclass`-like behavior. + :func:`dataclass `-like behavior. ``dataclass_transform`` may be used to decorate a class, metaclass, or a function that is itself a decorator. The presence of ``@dataclass_transform()`` tells a static type checker that the decorated object performs runtime "magic" that - transforms a class in a similar way to :func:`dataclasses.dataclass`. + transforms a class in a similar way to + :func:`@dataclasses.dataclass `. Example usage with a decorator function: @@ -2602,42 +2605,71 @@ Functions and decorators customize the default behaviors of the decorated class, metaclass, or function: - * ``eq_default`` indicates whether the ``eq`` parameter is assumed to be - ``True`` or ``False`` if it is omitted by the caller. - * ``order_default`` indicates whether the ``order`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``kw_only_default`` indicates whether the ``kw_only`` parameter is - assumed to be True or False if it is omitted by the caller. - * ``frozen_default`` indicates whether the ``frozen`` parameter is - assumed to be True or False if it is omitted by the caller. - - .. versionadded:: 3.12 - * ``field_specifiers`` specifies a static list of supported classes - or functions that describe fields, similar to ``dataclasses.field()``. - * Arbitrary other keyword arguments are accepted in order to allow for - possible future extensions. - - Type checkers recognize the following optional arguments on field + :param bool eq_default: + Indicates whether the ``eq`` parameter is assumed to be + ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``True``. + + :param bool order_default: + Indicates whether the ``order`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + :param bool kw_only_default: + Indicates whether the ``kw_only`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + :param bool frozen_default: + Indicates whether the ``frozen`` parameter is + assumed to be ``True`` or ``False`` if it is omitted by the caller. + Defaults to ``False``. + + .. versionadded:: 3.12 + + :param field_specifiers: + Specifies a static list of supported classes + or functions that describe fields, similar to :func:`dataclasses.field`. + Defaults to ``()``. + :type field_specifiers: tuple[Callable[..., Any], ...] + + :param Any \**kwargs: + Arbitrary other keyword arguments are accepted in order to allow for + possible future extensions. + + Type checkers recognize the following optional parameters on field specifiers: - * ``init`` indicates whether the field should be included in the - synthesized ``__init__`` method. If unspecified, ``init`` defaults to - ``True``. - * ``default`` provides the default value for the field. - * ``default_factory`` provides a runtime callback that returns the - default value for the field. If neither ``default`` nor - ``default_factory`` are specified, the field is assumed to have no - default value and must be provided a value when the class is - instantiated. - * ``factory`` is an alias for ``default_factory``. - * ``kw_only`` indicates whether the field should be marked as - keyword-only. If ``True``, the field will be keyword-only. If - ``False``, it will not be keyword-only. If unspecified, the value of - the ``kw_only`` parameter on the object decorated with - ``dataclass_transform`` will be used, or if that is unspecified, the - value of ``kw_only_default`` on ``dataclass_transform`` will be used. - * ``alias`` provides an alternative name for the field. This alternative - name is used in the synthesized ``__init__`` method. + .. list-table:: **Recognised parameters for field specifiers** + :header-rows: 1 + :widths: 20 80 + + * - Parameter name + - Description + * - ``init`` + - Indicates whether the field should be included in the + synthesized ``__init__`` method. If unspecified, ``init`` defaults to + ``True``. + * - ``default`` + - Provides the default value for the field. + * - ``default_factory`` + - Provides a runtime callback that returns the + default value for the field. If neither ``default`` nor + ``default_factory`` are specified, the field is assumed to have no + default value and must be provided a value when the class is + instantiated. + * - ``factory`` + - An alias for the ``default_factory`` parameter on field specifiers. + * - ``kw_only`` + - Indicates whether the field should be marked as + keyword-only. If ``True``, the field will be keyword-only. If + ``False``, it will not be keyword-only. If unspecified, the value of + the ``kw_only`` parameter on the object decorated with + ``dataclass_transform`` will be used, or if that is unspecified, the + value of ``kw_only_default`` on ``dataclass_transform`` will be used. + * - ``alias`` + - Provides an alternative name for the field. This alternative + name is used in the synthesized ``__init__`` method. At runtime, this decorator records its arguments in the ``__dataclass_transform__`` attribute on the decorated object. From da911a6b226ca47cc15088d800b575e19a731f1c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 15 Jun 2023 06:52:18 +0100 Subject: [PATCH 057/446] More reorganisation of the typing docs (#105787) --- Doc/library/typing.rst | 218 ++++++++++++++++++++++------------------- 1 file changed, 117 insertions(+), 101 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 859700e0c69b1d..77cc6bc59ea2a1 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2433,6 +2433,18 @@ These protocols are decorated with :func:`runtime_checkable`. An ABC with one abstract method ``__round__`` that is covariant in its return type. +ABCs for working with IO +------------------------ + +.. class:: IO + TextIO + BinaryIO + + Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` + and ``BinaryIO(IO[bytes])`` + represent the types of I/O streams such as returned by + :func:`open`. + Functions and decorators ------------------------ @@ -3052,11 +3064,15 @@ Constant .. versionadded:: 3.5.2 -Generic concrete collections ----------------------------- +.. _generic-concrete-collections: -Corresponding to built-in types -""""""""""""""""""""""""""""""" +Deprecated aliases +------------------ + +.. _corresponding-to-built-in-types: + +Aliases to built-in types +""""""""""""""""""""""""" .. class:: Dict(dict, MutableMapping[KT, VT]) @@ -3118,8 +3134,10 @@ Corresponding to built-in types .. note:: :data:`Tuple` is a special form. -Corresponding to types in :mod:`collections` -"""""""""""""""""""""""""""""""""""""""""""" +.. _corresponding-to-types-in-collections: + +Aliases to types in :mod:`collections` +"""""""""""""""""""""""""""""""""""""" .. class:: DefaultDict(collections.defaultdict, MutableMapping[KT, VT]) @@ -3174,17 +3192,10 @@ Corresponding to types in :mod:`collections` :class:`collections.deque` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -Other concrete types -"""""""""""""""""""" +.. _other-concrete-types: -.. class:: IO - TextIO - BinaryIO - - Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])`` - and ``BinaryIO(IO[bytes])`` - represent the types of I/O streams such as returned by - :func:`open`. +Aliases to other concrete types +""""""""""""""""""""""""""""""" .. class:: Pattern Match @@ -3223,11 +3234,11 @@ Other concrete types currently planned, but users are encouraged to use :class:`str` instead of ``Text``. -Abstract Base Classes ---------------------- +.. _abstract-base-classes: +.. _corresponding-to-collections-in-collections-abc: -Corresponding to collections in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" +Aliases to container ABCs in :mod:`collections.abc` +""""""""""""""""""""""""""""""""""""""""""""""""""" .. class:: AbstractSet(Collection[T_co]) @@ -3342,86 +3353,10 @@ Corresponding to collections in :mod:`collections.abc` :class:`collections.abc.ValuesView` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -Corresponding to other types in :mod:`collections.abc` -"""""""""""""""""""""""""""""""""""""""""""""""""""""" - -.. class:: Iterable(Generic[T_co]) - - Deprecated alias to :class:`collections.abc.Iterable`. - - .. deprecated:: 3.9 - :class:`collections.abc.Iterable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Iterator(Iterable[T_co]) - - Deprecated alias to :class:`collections.abc.Iterator`. - - .. deprecated:: 3.9 - :class:`collections.abc.Iterator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) - - Deprecated alias to :class:`collections.abc.Generator`. - - A generator can be annotated by the generic type - ``Generator[YieldType, SendType, ReturnType]``. For example:: - - def echo_round() -> Generator[int, float, str]: - sent = yield 0 - while sent >= 0: - sent = yield round(sent) - return 'Done' - - Note that unlike many other generics in the typing module, the ``SendType`` - of :class:`Generator` behaves contravariantly, not covariantly or - invariantly. - - If your generator will only yield values, set the ``SendType`` and - ``ReturnType`` to ``None``:: - - def infinite_stream(start: int) -> Generator[int, None, None]: - while True: - yield start - start += 1 - - Alternatively, annotate your generator as having a return type of - either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: - - def infinite_stream(start: int) -> Iterator[int]: - while True: - yield start - start += 1 - - .. deprecated:: 3.9 - :class:`collections.abc.Generator` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Hashable - - Deprecated alias to :class:`collections.abc.Hashable`. - - .. deprecated:: 3.12 - Use :class:`collections.abc.Hashable` directly instead. - -.. class:: Reversible(Iterable[T_co]) - - Deprecated alias to :class:`collections.abc.Reversible`. +.. _asynchronous-programming: - .. deprecated:: 3.9 - :class:`collections.abc.Reversible` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - -.. class:: Sized - - Deprecated alias to :class:`collections.abc.Sized`. - - .. deprecated:: 3.12 - Use :class:`collections.abc.Sized` directly instead. - -Asynchronous programming -"""""""""""""""""""""""" +Aliases to asynchronous ABCs in :mod:`collections.abc` +"""""""""""""""""""""""""""""""""""""""""""""""""""""" .. class:: Coroutine(Awaitable[ReturnType], Generic[YieldType, SendType, ReturnType]) @@ -3512,9 +3447,90 @@ Asynchronous programming :class:`collections.abc.Awaitable` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. _corresponding-to-other-types-in-collections-abc: + +Aliases to other ABCs in :mod:`collections.abc` +""""""""""""""""""""""""""""""""""""""""""""""" + +.. class:: Iterable(Generic[T_co]) + + Deprecated alias to :class:`collections.abc.Iterable`. + + .. deprecated:: 3.9 + :class:`collections.abc.Iterable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Iterator(Iterable[T_co]) + + Deprecated alias to :class:`collections.abc.Iterator`. + + .. deprecated:: 3.9 + :class:`collections.abc.Iterator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) + + Deprecated alias to :class:`collections.abc.Generator`. + + A generator can be annotated by the generic type + ``Generator[YieldType, SendType, ReturnType]``. For example:: + + def echo_round() -> Generator[int, float, str]: + sent = yield 0 + while sent >= 0: + sent = yield round(sent) + return 'Done' + + Note that unlike many other generics in the typing module, the ``SendType`` + of :class:`Generator` behaves contravariantly, not covariantly or + invariantly. + + If your generator will only yield values, set the ``SendType`` and + ``ReturnType`` to ``None``:: + + def infinite_stream(start: int) -> Generator[int, None, None]: + while True: + yield start + start += 1 + + Alternatively, annotate your generator as having a return type of + either ``Iterable[YieldType]`` or ``Iterator[YieldType]``:: + + def infinite_stream(start: int) -> Iterator[int]: + while True: + yield start + start += 1 + + .. deprecated:: 3.9 + :class:`collections.abc.Generator` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Hashable + + Deprecated alias to :class:`collections.abc.Hashable`. + + .. deprecated:: 3.12 + Use :class:`collections.abc.Hashable` directly instead. + +.. class:: Reversible(Iterable[T_co]) + + Deprecated alias to :class:`collections.abc.Reversible`. + + .. deprecated:: 3.9 + :class:`collections.abc.Reversible` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + +.. class:: Sized + + Deprecated alias to :class:`collections.abc.Sized`. + + .. deprecated:: 3.12 + Use :class:`collections.abc.Sized` directly instead. + +.. _context-manager-types: -Context manager types -""""""""""""""""""""" +Aliases to :mod:`contextlib` ABCs +""""""""""""""""""""""""""""""""" .. class:: ContextManager(Generic[T_co]) From 0841ca7932987f30a2a23d39f3e6e141622d6fea Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Jun 2023 11:31:09 +0200 Subject: [PATCH 058/446] gh-105751: Remove dead code in test_ctypes (#105817) * Remove "except: print(tp); raise" debug code. * Remove unused NoNullHandle() function. * Remove commented code. --- Lib/test/test_ctypes/test_as_parameter.py | 2 - Lib/test/test_ctypes/test_bitfields.py | 2 - Lib/test/test_ctypes/test_callbacks.py | 5 -- Lib/test/test_ctypes/test_find.py | 2 +- Lib/test/test_ctypes/test_funcptr.py | 22 ------ Lib/test/test_ctypes/test_functions.py | 6 -- Lib/test/test_ctypes/test_internals.py | 6 -- Lib/test/test_ctypes/test_keeprefs.py | 8 --- Lib/test/test_ctypes/test_numbers.py | 2 - Lib/test/test_ctypes/test_parameters.py | 2 - Lib/test/test_ctypes/test_pep3118.py | 82 ++++++++++------------- Lib/test/test_ctypes/test_pointers.py | 17 ----- Lib/test/test_ctypes/test_refcounts.py | 1 - Lib/test/test_ctypes/test_strings.py | 3 - Lib/test/test_ctypes/test_structures.py | 5 -- 15 files changed, 37 insertions(+), 128 deletions(-) diff --git a/Lib/test/test_ctypes/test_as_parameter.py b/Lib/test/test_ctypes/test_as_parameter.py index e842d526c53af0..39f70e864757d5 100644 --- a/Lib/test/test_ctypes/test_as_parameter.py +++ b/Lib/test/test_ctypes/test_as_parameter.py @@ -81,7 +81,6 @@ def test_callbacks(self): MyCallback = CFUNCTYPE(c_int, c_int) def callback(value): - #print "called back with", value return value cb = MyCallback(callback) @@ -118,7 +117,6 @@ def test_callbacks_2(self): f.argtypes = [c_int, MyCallback] def callback(value): - #print "called back with", value self.assertEqual(type(value), int) return value diff --git a/Lib/test/test_ctypes/test_bitfields.py b/Lib/test/test_ctypes/test_bitfields.py index d8eb2d668a6a93..d43c56ad371fbd 100644 --- a/Lib/test/test_ctypes/test_bitfields.py +++ b/Lib/test/test_ctypes/test_bitfields.py @@ -31,8 +31,6 @@ class BITS(Structure): func = CDLL(_ctypes_test.__file__).unpack_bitfields func.argtypes = POINTER(BITS), c_char -##for n in "ABCDEFGHIMNOPQRS": -## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset class C_Test(unittest.TestCase): diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 582677b832e5cb..98341bc5610b79 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -19,9 +19,6 @@ class Callbacks(unittest.TestCase): functype = CFUNCTYPE -## def tearDown(self): -## gc.collect() - def callback(self, *args): self.got_args = args return args[-1] @@ -43,8 +40,6 @@ def check_type(self, typ, arg): self.assertEqual(self.got_args, (-3, arg)) self.assertEqual(result, arg) - ################ - def test_byte(self): self.check_type(c_byte, 42) self.check_type(c_byte, -42) diff --git a/Lib/test/test_ctypes/test_find.py b/Lib/test/test_ctypes/test_find.py index 7a1658b63cbac7..66ff23e72b5e10 100644 --- a/Lib/test/test_ctypes/test_find.py +++ b/Lib/test/test_ctypes/test_find.py @@ -23,7 +23,7 @@ def setUpClass(cls): lib_glu = find_library("GLU") lib_gle = find_library("gle") - ## print, for debugging + # print, for debugging if test.support.verbose: print("OpenGL libraries:") for item in (("GL", lib_gl), diff --git a/Lib/test/test_ctypes/test_funcptr.py b/Lib/test/test_ctypes/test_funcptr.py index 0ea3f3581bbaa6..2ad40647e0cfbb 100644 --- a/Lib/test/test_ctypes/test_funcptr.py +++ b/Lib/test/test_ctypes/test_funcptr.py @@ -73,17 +73,9 @@ class WNDCLASS(Structure): WNDPROC_2 = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int) - # This is no longer true, now that WINFUNCTYPE caches created types internally. - ## # CFuncPtr subclasses are compared by identity, so this raises a TypeError: - ## self.assertRaises(TypeError, setattr, wndclass, - ## "lpfnWndProc", WNDPROC_2(wndproc)) - # instead: - self.assertIs(WNDPROC, WNDPROC_2) - # 'wndclass.lpfnWndProc' leaks 94 references. Why? self.assertEqual(wndclass.lpfnWndProc(1, 2, 3, 4), 10) - f = wndclass.lpfnWndProc del wndclass @@ -92,24 +84,14 @@ class WNDCLASS(Structure): self.assertEqual(f(10, 11, 12, 13), 46) def test_dllfunctions(self): - - def NoNullHandle(value): - if not value: - raise ctypes.WinError() - return value - strchr = lib.my_strchr strchr.restype = c_char_p strchr.argtypes = (c_char_p, c_char) self.assertEqual(strchr(b"abcdefghi", b"b"), b"bcdefghi") self.assertEqual(strchr(b"abcdefghi", b"x"), None) - strtok = lib.my_strtok strtok.restype = c_char_p - # Neither of this does work: strtok changes the buffer it is passed -## strtok.argtypes = (c_char_p, c_char_p) -## strtok.argtypes = (c_string, c_char_p) def c_string(init): size = len(init) + 1 @@ -118,10 +100,6 @@ def c_string(init): s = b"a\nb\nc" b = c_string(s) -## b = (c_char * (len(s)+1))() -## b.value = s - -## b = c_string(s) self.assertEqual(strtok(b, b"\n"), b"a") self.assertEqual(strtok(None, b"\n"), b"b") self.assertEqual(strtok(None, b"\n"), b"c") diff --git a/Lib/test/test_ctypes/test_functions.py b/Lib/test/test_ctypes/test_functions.py index f8591463c18ad0..9cf680f16620ac 100644 --- a/Lib/test/test_ctypes/test_functions.py +++ b/Lib/test/test_ctypes/test_functions.py @@ -227,7 +227,6 @@ def test_pointers(self): result = f(byref(c_int(99))) self.assertNotEqual(result.contents, 99) - ################################################################ def test_shorts(self): f = dll._testfunc_callback_i_if @@ -245,9 +244,6 @@ def callback(v): f(2**18, cb) self.assertEqual(args, expected) - ################################################################ - - def test_callbacks(self): f = dll._testfunc_callback_i_if f.restype = c_int @@ -256,7 +252,6 @@ def test_callbacks(self): MyCallback = CFUNCTYPE(c_int, c_int) def callback(value): - #print "called back with", value return value cb = MyCallback(callback) @@ -289,7 +284,6 @@ def test_callbacks_2(self): f.argtypes = [c_int, MyCallback] def callback(value): - #print "called back with", value self.assertEqual(type(value), int) return value diff --git a/Lib/test/test_ctypes/test_internals.py b/Lib/test/test_ctypes/test_internals.py index 763a5e8b0f0858..94c9a86c2d06df 100644 --- a/Lib/test/test_ctypes/test_internals.py +++ b/Lib/test/test_ctypes/test_internals.py @@ -80,9 +80,6 @@ class Y(Structure): y = Y() y.x = x self.assertEqual(y._objects, {"0": {"0": s1, "1": s2}}) -## x = y.x -## del y -## print x._b_base_._objects def test_ptr_struct(self): class X(Structure): @@ -94,9 +91,6 @@ class X(Structure): x = X() x.data = a -##XXX print x._objects -##XXX print x.data[0] -##XXX print x.data._objects if __name__ == '__main__': diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index f93e3f2676945c..92dd1a08b69200 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -115,19 +115,14 @@ class X(Structure): c_int(99) x.p[0] print(x.p[0]) -## del x -## print "2?", sys.getrefcount(i) -## del i gc.collect() for i in range(320): c_int(99) x.p[0] print(x.p[0]) print(x.p.contents) -## print x._objects x.p[0] = "spam spam" -## print x.p[0] print("+" * 42) print(x._objects) @@ -144,9 +139,6 @@ class RECT(Structure): r.a = pointer(p1) r.b = pointer(p1) -## from pprint import pprint as pp -## pp(p1._objects) -## pp(r._objects) r.a[0].x = 42 r.a[0].y = 99 diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 052900f519c0b9..7cf0c3235d188c 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -225,7 +225,6 @@ class c_int_S(_SimpleCData): def run_test(rep, msg, func, arg=None): -## items = [None] * rep items = range(rep) from time import perf_counter as clock if arg is not None: @@ -243,7 +242,6 @@ def run_test(rep, msg, func, arg=None): def check_perf(): # Construct 5 objects - from ctypes import c_int REP = 200000 diff --git a/Lib/test/test_ctypes/test_parameters.py b/Lib/test/test_ctypes/test_parameters.py index f43819f004996c..40979212a627d8 100644 --- a/Lib/test/test_ctypes/test_parameters.py +++ b/Lib/test/test_ctypes/test_parameters.py @@ -103,8 +103,6 @@ def test_c_wchar(self): def test_int_pointers(self): LPINT = POINTER(c_int) -## p = pointer(c_int(42)) -## x = LPINT.from_param(p) x = LPINT.from_param(pointer(c_int(42))) self.assertEqual(x.contents.value, 42) self.assertEqual(LPINT(c_int(42)).contents.value, 42) diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index caecbc8def8815..06b2ccecade44e 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -31,57 +31,47 @@ def test_native_types(self): for tp, fmt, shape, itemtp in native_types: ob = tp() v = memoryview(ob) - try: - self.assertEqual(normalize(v.format), normalize(fmt)) - if shape: - self.assertEqual(len(v), shape[0]) - else: - self.assertRaises(TypeError, len, v) - self.assertEqual(v.itemsize, sizeof(itemtp)) - self.assertEqual(v.shape, shape) - # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides - # if requested. memoryview currently reconstructs missing - # stride information, so this assert will fail. - # self.assertEqual(v.strides, ()) - - # they are always read/write - self.assertFalse(v.readonly) - - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n * v.itemsize, len(v.tobytes())) - except: - # so that we can see the failing type - print(tp) - raise + self.assertEqual(normalize(v.format), normalize(fmt)) + if shape: + self.assertEqual(len(v), shape[0]) + else: + self.assertRaises(TypeError, len, v) + self.assertEqual(v.itemsize, sizeof(itemtp)) + self.assertEqual(v.shape, shape) + # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides + # if requested. memoryview currently reconstructs missing + # stride information, so this assert will fail. + # self.assertEqual(v.strides, ()) + + # they are always read/write + self.assertFalse(v.readonly) + + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) def test_endian_types(self): for tp, fmt, shape, itemtp in endian_types: ob = tp() v = memoryview(ob) - try: - self.assertEqual(v.format, fmt) - if shape: - self.assertEqual(len(v), shape[0]) - else: - self.assertRaises(TypeError, len, v) - self.assertEqual(v.itemsize, sizeof(itemtp)) - self.assertEqual(v.shape, shape) - # XXX Issue #12851 - # self.assertEqual(v.strides, ()) - - # they are always read/write - self.assertFalse(v.readonly) - - n = 1 - for dim in v.shape: - n = n * dim - self.assertEqual(n * v.itemsize, len(v.tobytes())) - except: - # so that we can see the failing type - print(tp) - raise + self.assertEqual(v.format, fmt) + if shape: + self.assertEqual(len(v), shape[0]) + else: + self.assertRaises(TypeError, len, v) + self.assertEqual(v.itemsize, sizeof(itemtp)) + self.assertEqual(v.shape, shape) + # XXX Issue #12851 + # self.assertEqual(v.strides, ()) + + # they are always read/write + self.assertFalse(v.readonly) + + n = 1 + for dim in v.shape: + n = n * dim + self.assertEqual(n * v.itemsize, len(v.tobytes())) # define some structure classes diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index fd30109aa521b2..8410174358c19d 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -37,7 +37,6 @@ def test_pass_pointers(self): func.restype = c_long i = c_int(12345678) -## func.argtypes = (POINTER(c_int),) address = func(byref(i)) self.assertEqual(c_int.from_address(address).value, 12345678) @@ -80,9 +79,7 @@ def test_callbacks_with_pointers(self): def func(arg): for i in range(10): -## print arg[i], self.result.append(arg[i]) -## print return 0 callback = PROTOTYPE(func) @@ -92,25 +89,15 @@ def func(arg): # The int pointer points to a table containing the numbers 1..10 doit = dll._testfunc_callback_with_pointer -## i = c_int(42) -## callback(byref(i)) -## self.assertEqual(i.value, 84) - doit(callback) -## print self.result doit(callback) -## print self.result def test_basics(self): for ct, pt in zip(ctype_types, python_types): i = ct(42) p = pointer(i) -## print type(p.contents), ct self.assertIs(type(p.contents), ct) # p.contents is the same as p[0] -## print p.contents -## self.assertEqual(p.contents, 42) -## self.assertEqual(p[0], 42) with self.assertRaises(TypeError): del p[0] @@ -118,11 +105,7 @@ def test_basics(self): def test_from_address(self): a = array.array('i', [100, 200, 300, 400, 500]) addr = a.buffer_info()[0] - p = POINTER(POINTER(c_int)) -## print dir(p) -## print p.from_address -## print p.from_address(addr)[0][0] def test_other(self): class Table(Structure): diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index a1fe89105aee9c..a90588ca9bb1b6 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -20,7 +20,6 @@ def test_1(self): f.argtypes = [ctypes.c_int, MyCallback] def callback(value): - #print "called back with", value return value self.assertEqual(sys.getrefcount(callback), 2) diff --git a/Lib/test/test_ctypes/test_strings.py b/Lib/test/test_ctypes/test_strings.py index 26f036adfb7585..13d4000ea033c4 100644 --- a/Lib/test/test_ctypes/test_strings.py +++ b/Lib/test/test_ctypes/test_strings.py @@ -46,13 +46,10 @@ def test_create_string_buffer_raw(self): def test_param_1(self): BUF = c_char * 4 buf = BUF() -## print c_char_p.from_param(buf) def test_param_2(self): BUF = c_char * 4 buf = BUF() -## print BUF.from_param(c_char_p("python")) -## print BUF.from_param(BUF(*"pyth")) def test_del_segfault(self): BUF = c_char * 4 diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index e656d18934779f..46bf90054be66a 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -381,9 +381,6 @@ class X(Structure): self.assertEqual((cls, msg), (TypeError, "abstract class")) def test_methods(self): -## class X(Structure): -## _fields_ = [] - self.assertIn("in_dll", dir(type(Structure))) self.assertIn("from_address", dir(type(Structure))) self.assertIn("in_dll", dir(type(Structure))) @@ -770,8 +767,6 @@ class S(Structure): s.array[0] = 1 -## s.array[1] = 42 - items = [s.array[i] for i in range(3)] self.assertEqual(items, [1, 2, 3]) From b496ff31091d0b2530c804e64b9e84e4e154268c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Jun 2023 11:36:41 +0200 Subject: [PATCH 059/446] gh-105751: Reenable disable test_ctypes tests (#105818) Reenable 3 tests: * test_overflow() * test_basic_wstrings() * test_toolong() --- Lib/test/test_ctypes/test_memfunctions.py | 7 ++-- Lib/test/test_ctypes/test_strings.py | 49 ++++++++++------------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_ctypes/test_memfunctions.py b/Lib/test/test_ctypes/test_memfunctions.py index 2ff95f619e0895..112b27ba48e07e 100644 --- a/Lib/test/test_ctypes/test_memfunctions.py +++ b/Lib/test/test_ctypes/test_memfunctions.py @@ -9,16 +9,15 @@ class MemFunctionsTest(unittest.TestCase): - @unittest.skip('test disabled') def test_overflow(self): # string_at and wstring_at must use the Python calling # convention (which acquires the GIL and checks the Python # error flag). Provoke an error and catch it; see also issue - # #3554: + # gh-47804. self.assertRaises((OverflowError, MemoryError, SystemError), - lambda: wstring_at(u"foo", sys.maxint - 1)) + lambda: wstring_at(u"foo", sys.maxsize - 1)) self.assertRaises((OverflowError, MemoryError, SystemError), - lambda: string_at("foo", sys.maxint - 1)) + lambda: string_at("foo", sys.maxsize - 1)) def test_memmove(self): # large buffers apparently increase the chance that the memory diff --git a/Lib/test/test_ctypes/test_strings.py b/Lib/test/test_ctypes/test_strings.py index 13d4000ea033c4..3ecc6fe180adf7 100644 --- a/Lib/test/test_ctypes/test_strings.py +++ b/Lib/test/test_ctypes/test_strings.py @@ -1,5 +1,6 @@ import unittest -from ctypes import create_string_buffer, sizeof, byref, c_char, c_wchar +from ctypes import (create_string_buffer, create_unicode_buffer, + sizeof, byref, c_char, c_wchar) class StringArrayTestCase(unittest.TestCase): @@ -88,41 +89,35 @@ def test_wchar(self): repr(byref(c_wchar("x"))) c_wchar("x") - @unittest.skip('test disabled') def test_basic_wstrings(self): - cs = c_wstring("abcdef") - - # XXX This behaviour is about to change: - # len returns the size of the internal buffer in bytes. - # This includes the terminating NUL character. - self.assertEqual(sizeof(cs), 14) - - # The value property is the string up to the first terminating NUL. + cs = create_unicode_buffer("abcdef") self.assertEqual(cs.value, "abcdef") - self.assertEqual(c_wstring("abc\000def").value, "abc") - self.assertEqual(c_wstring("abc\000def").value, "abc") + # value can be changed + cs.value = "abc" + self.assertEqual(cs.value, "abc") + + # string is truncated at NUL character + cs.value = "def\0z" + self.assertEqual(cs.value, "def") - # The raw property is the total buffer contents: - self.assertEqual(cs.raw, "abcdef\000") - self.assertEqual(c_wstring("abc\000def").raw, "abc\000def\000") + self.assertEqual(create_unicode_buffer("abc\0def").value, "abc") - # We can change the value: - cs.value = "ab" - self.assertEqual(cs.value, "ab") - self.assertEqual(cs.raw, "ab\000\000\000\000\000") + # created with an empty string + cs = create_unicode_buffer(3) + self.assertEqual(cs.value, "") - self.assertRaises(TypeError, c_wstring, "123") - self.assertRaises(ValueError, c_wstring, 0) + cs.value = "abc" + self.assertEqual(cs.value, "abc") - @unittest.skip('test disabled') def test_toolong(self): - cs = c_wstring("abcdef") - # Much too long string: - self.assertRaises(ValueError, setattr, cs, "value", "123456789012345") + cs = create_unicode_buffer("abc") + with self.assertRaises(ValueError): + cs.value = "abcdef" - # One char too long values: - self.assertRaises(ValueError, setattr, cs, "value", "1234567") + cs = create_unicode_buffer(4) + with self.assertRaises(ValueError): + cs.value = "abcdef" def run_test(rep, msg, func, arg): From c5111aec2bac464b6643e21fe0844c9b8c4c661a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Jun 2023 11:44:54 +0200 Subject: [PATCH 060/446] gh-105751: Remove platform usage in test_ctypes (#105819) The MACHINE variable is no longer used in test_structures. --- Lib/test/test_ctypes/test_structures.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 46bf90054be66a..72bec13a77ca52 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -1,5 +1,4 @@ import _ctypes_test -import platform import struct import sys import unittest @@ -12,12 +11,6 @@ from test import support -# The following definition is meant to be used from time to time to assist -# temporarily disabling tests on specific architectures while investigations -# are in progress, to keep buildbots happy. -MACHINE = platform.machine() - - class SubclassesTest(unittest.TestCase): def test_subclass(self): class X(Structure): From 09ce8c3b48f940eb8865330f029b8069854c3106 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 15 Jun 2023 11:48:01 +0100 Subject: [PATCH 061/446] gh-105821: Use a raw f-string in test_httpservers.py (#105822) Use a raw f-string in test_httpservers.py --- Lib/test/test_httpservers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index cdd1bea754a020..cfd8a101dcc1c1 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -442,10 +442,10 @@ def test_undecodable_filename(self): def test_undecodable_parameter(self): # sanity check using a valid parameter response = self.request(self.base_url + '/?x=123').read() - self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1')) + self.assertRegex(response, rf'listing for {self.base_url}/\?x=123'.encode('latin1')) # now the bogus encoding response = self.request(self.base_url + '/?x=%bb').read() - self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) + self.assertRegex(response, rf'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1')) def test_get_dir_redirect_location_domain_injection_bug(self): """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location. From 8f10140e74d141a0a894702044e213e6f0690d9c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Jun 2023 14:22:01 +0200 Subject: [PATCH 062/446] gh-105751, test_ctypes: Remove disabled tests (#105826) * The following tests were disabled since the initial ctypes commit in 2006, commit babddfca758abe34ff12023f63b18d745fae7ca9: * Callbacks.test_char_p() * DeletePointerTestCase.test_X() * NumberTestCase.test_perf() * StructureTestCase.test_subclass_creation() * Tests.test_X() of test_byteswap * NumberTestCase.test_bool_from_address() was disabled in 2007 by commit 5dc4fe09b7648f9801558e766b21a3d3b2dcad3b. * Remove check_perf() and run_test() of test_numbers. --- Lib/test/test_ctypes/test_byteswap.py | 8 --- Lib/test/test_ctypes/test_callbacks.py | 10 +--- Lib/test/test_ctypes/test_keeprefs.py | 28 --------- Lib/test/test_ctypes/test_numbers.py | 78 +------------------------ Lib/test/test_ctypes/test_structures.py | 9 --- 5 files changed, 2 insertions(+), 131 deletions(-) diff --git a/Lib/test/test_ctypes/test_byteswap.py b/Lib/test/test_ctypes/test_byteswap.py index 2986e8a177a405..b97b57646ecd71 100644 --- a/Lib/test/test_ctypes/test_byteswap.py +++ b/Lib/test/test_ctypes/test_byteswap.py @@ -25,14 +25,6 @@ def bin(s): # For Structures and Unions, these types are created on demand. class Test(unittest.TestCase): - @unittest.skip('test disabled') - def test_X(self): - print(sys.byteorder, file=sys.stderr) - for i in range(32): - bits = BITS() - setattr(bits, "i%s" % i, 1) - dump(bits) - def test_slots(self): class BigPoint(BigEndianStructure): __slots__ = () diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index 98341bc5610b79..037677e37ab34a 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -8,7 +8,7 @@ from _ctypes import CTYPES_MAX_ARGCOUNT from ctypes import (CDLL, cdll, Structure, CFUNCTYPE, ArgumentError, POINTER, sizeof, - c_byte, c_ubyte, c_char, c_char_p, + c_byte, c_ubyte, c_char, c_short, c_ushort, c_int, c_uint, c_long, c_longlong, c_ulonglong, c_ulong, c_float, c_double, c_longdouble, py_object) @@ -92,14 +92,6 @@ def test_char(self): self.check_type(c_char, b"x") self.check_type(c_char, b"a") - # disabled: would now (correctly) raise a RuntimeWarning about - # a memory leak. A callback function cannot return a non-integral - # C type without causing a memory leak. - @unittest.skip('test disabled') - def test_char_p(self): - self.check_type(c_char_p, "abc") - self.check_type(c_char_p, "def") - def test_pyobject(self): o = () for o in (), [], object(): diff --git a/Lib/test/test_ctypes/test_keeprefs.py b/Lib/test/test_ctypes/test_keeprefs.py index 92dd1a08b69200..23b03b64b4a716 100644 --- a/Lib/test/test_ctypes/test_keeprefs.py +++ b/Lib/test/test_ctypes/test_keeprefs.py @@ -1,5 +1,3 @@ -import gc -import sys import unittest from ctypes import (Structure, POINTER, pointer, _pointer_type_cache, c_char_p, c_int) @@ -101,32 +99,6 @@ def test_p_cint(self): self.assertEqual(x._objects, {'1': i}) -class DeletePointerTestCase(unittest.TestCase): - @unittest.skip('test disabled') - def test_X(self): - class X(Structure): - _fields_ = [("p", POINTER(c_char_p))] - x = X() - i = c_char_p("abc def") - print("2?", sys.getrefcount(i)) - x.p = pointer(i) - print("3?", sys.getrefcount(i)) - for i in range(320): - c_int(99) - x.p[0] - print(x.p[0]) - gc.collect() - for i in range(320): - c_int(99) - x.p[0] - print(x.p[0]) - print(x.p.contents) - - x.p[0] = "spam spam" - print("+" * 42) - print(x._objects) - - class PointerToStructure(unittest.TestCase): def test(self): class POINT(Structure): diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index 7cf0c3235d188c..fd318f9a18e533 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -3,7 +3,7 @@ import sys import unittest from operator import truth -from ctypes import (byref, sizeof, alignment, _SimpleCData, +from ctypes import (byref, sizeof, alignment, c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double, c_longdouble, c_bool) @@ -70,14 +70,6 @@ def test_typeerror(self): self.assertRaises(TypeError, t, "") self.assertRaises(TypeError, t, None) - @unittest.skip('test disabled') - def test_valid_ranges(self): - # invalid values of the correct type - # raise ValueError (not OverflowError) - for t, (l, h) in zip(unsigned_types, unsigned_ranges): - self.assertRaises(ValueError, t, l-1) - self.assertRaises(ValueError, t, h+1) - def test_from_param(self): # the from_param class method attribute always # returns PyCArgObject instances @@ -188,17 +180,6 @@ def test_char_from_address(self): a[0] = ord('?') self.assertEqual(v.value, b'?') - # array does not support c_bool / 't' - @unittest.skip('test disabled') - def test_bool_from_address(self): - a = array.array(c_bool._type_, [True]) - v = t.from_address(a.buffer_info()[0]) - self.assertEqual(v.value, a[0]) - self.assertEqual(type(v) is t) - a[0] = False - self.assertEqual(v.value, a[0]) - self.assertEqual(type(v) is t) - def test_init(self): # c_int() can be initialized from Python's int, and c_int. # Not from c_long or so, which seems strange, abc should @@ -214,63 +195,6 @@ def test_float_overflow(self): if (hasattr(t, "__ctype_le__")): self.assertRaises(OverflowError, t.__ctype_le__, big_int) - @unittest.skip('test disabled') - def test_perf(self): - check_perf() - - -class c_int_S(_SimpleCData): - _type_ = "i" - __slots__ = [] - - -def run_test(rep, msg, func, arg=None): - items = range(rep) - from time import perf_counter as clock - if arg is not None: - start = clock() - for i in items: - func(arg); func(arg); func(arg); func(arg); func(arg) - stop = clock() - else: - start = clock() - for i in items: - func(); func(); func(); func(); func() - stop = clock() - print("%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep))) - - -def check_perf(): - # Construct 5 objects - - REP = 200000 - - run_test(REP, "int()", int) - run_test(REP, "int(999)", int) - run_test(REP, "c_int()", c_int) - run_test(REP, "c_int(999)", c_int) - run_test(REP, "c_int_S()", c_int_S) - run_test(REP, "c_int_S(999)", c_int_S) - -# Python 2.3 -OO, win2k, P4 700 MHz: -# -# int(): 0.87 us -# int(999): 0.87 us -# c_int(): 3.35 us -# c_int(999): 3.34 us -# c_int_S(): 3.23 us -# c_int_S(999): 3.24 us - -# Python 2.2 -OO, win2k, P4 700 MHz: -# -# int(): 0.89 us -# int(999): 0.89 us -# c_int(): 9.99 us -# c_int(999): 10.02 us -# c_int_S(): 9.87 us -# c_int_S(999): 9.85 us - if __name__ == '__main__': -## check_perf() unittest.main() diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 72bec13a77ca52..f05ee5e491a41e 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -357,15 +357,6 @@ def get_except(self, func, *args): except Exception as detail: return detail.__class__, str(detail) - @unittest.skip('test disabled') - def test_subclass_creation(self): - meta = type(Structure) - # same as 'class X(Structure): pass' - # fails, since we need either a _fields_ or a _abstract_ attribute - cls, msg = self.get_except(meta, "X", (Structure,), {}) - self.assertEqual((cls, msg), - (AttributeError, "class must define a '_fields_' attribute")) - def test_abstract_class(self): class X(Structure): _abstract_ = "something" From d382ad49157b3802fc5619f68d96810def517869 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Thu, 15 Jun 2023 18:21:24 +0200 Subject: [PATCH 063/446] gh-105820: Fix tok_mode expression buffer in file & readline tokenizer (#105828) --- Lib/test/test_fstring.py | 15 ++++++++++++++- Lib/test/test_tokenize.py | 13 +++++++++++++ ...2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst | 1 + Parser/tokenizer.c | 11 ++++++++--- 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index cbb03080f797bc..8f6b576b5f785f 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -15,7 +15,7 @@ import unittest from test import support from test.support.os_helper import temp_cwd -from test.support.script_helper import assert_python_failure +from test.support.script_helper import assert_python_failure, assert_python_ok a_global = 'global variable' @@ -1635,5 +1635,18 @@ def test_syntax_error_after_debug(self): "f'{1=}{1;}'", ]) + def test_debug_in_file(self): + with temp_cwd(): + script = 'script.py' + with open('script.py', 'w') as f: + f.write(f"""\ +print(f'''{{ +3 +=}}''')""") + + _, stdout, _ = assert_python_ok(script) + self.assertEqual(stdout.decode('utf-8').strip().replace('\r\n', '\n').replace('\r', '\n'), + "3\n=3") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 15f53632cff814..5ad278499c9df9 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -558,6 +558,19 @@ def test_string(self): OP '}' (1, 39) (1, 40) FSTRING_MIDDLE ' final words' (1, 40) (1, 52) FSTRING_END "'" (1, 52) (1, 53) + """) + self.check_tokenize("""\ +f'''{ +3 +=}'''""", """\ + FSTRING_START "f'''" (1, 0) (1, 4) + OP '{' (1, 4) (1, 5) + NL '\\n' (1, 5) (1, 6) + NUMBER '3' (2, 0) (2, 1) + NL '\\n' (2, 1) (2, 2) + OP '=' (3, 0) (3, 1) + OP '}' (3, 1) (3, 2) + FSTRING_END "'''" (3, 2) (3, 5) """) def test_function(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst new file mode 100644 index 00000000000000..df42b9e1d5a40f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst @@ -0,0 +1 @@ +Fix an f-string bug, where using a debug expression (the `=` sign) that appears in the last line of a file results to the debug buffer that holds the expression text being one character too small. diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 5d01b8e8a5ac20..4f7b1f8114e96f 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1039,9 +1039,6 @@ tok_readline_raw(struct tok_state *tok) if (line == NULL) { return 1; } - if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { - return 0; - } if (tok->fp_interactive && tok_concatenate_interactive_new_line(tok, line) == -1) { return 0; @@ -1270,6 +1267,10 @@ tok_underflow_file(struct tok_state *tok) { tok->implicit_newline = 1; } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } + ADVANCE_LINENO(); if (tok->decoding_state != STATE_NORMAL) { if (tok->lineno > 2) { @@ -1314,6 +1315,10 @@ tok_underflow_readline(struct tok_state* tok) { tok->implicit_newline = 1; } + if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) { + return 0; + } + ADVANCE_LINENO(); /* The default encoding is UTF-8, so make sure we don't have any non-UTF-8 sequences in it. */ From 3af2dc7588614c65e9d1178ad9b4a11a19c14dde Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Thu, 15 Jun 2023 19:10:33 +0200 Subject: [PATCH 064/446] gh-105831: Fix NEWS blurb from gh-105828 (#105833) --- .../2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst index df42b9e1d5a40f..407940add56752 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-15-54-47.gh-issue-105831.-MC9Zs.rst @@ -1 +1,3 @@ -Fix an f-string bug, where using a debug expression (the `=` sign) that appears in the last line of a file results to the debug buffer that holds the expression text being one character too small. +Fix an f-string bug, where using a debug expression (the ``=`` sign) that +appears in the last line of a file results to the debug buffer that holds the +expression text being one character too small. From a4056c8f9c2d9970d39e3cb6bffb255cd4b8a42c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 15 Jun 2023 15:45:13 -0700 Subject: [PATCH 065/446] GH-105588: Add missing error checks to some obj2ast_* converters (GH-105589) --- Lib/test/test_ast.py | 27 +++++++++++++++++++ ...-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst | 2 ++ Parser/asdl_c.py | 1 + Python/Python-ast.c | 7 +++++ 4 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index ffd082ec11806a..a03fa4c7187b05 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -3,6 +3,7 @@ import dis import enum import os +import re import sys import textwrap import types @@ -1110,6 +1111,32 @@ def test_null_bytes(self): msg="source code string cannot contain null bytes"): ast.parse("a\0b") + def assert_none_check(self, node: type[ast.AST], attr: str, source: str) -> None: + with self.subTest(f"{node.__name__}.{attr}"): + tree = ast.parse(source) + found = 0 + for child in ast.walk(tree): + if isinstance(child, node): + setattr(child, attr, None) + found += 1 + self.assertEqual(found, 1) + e = re.escape(f"field '{attr}' is required for {node.__name__}") + with self.assertRaisesRegex(ValueError, f"^{e}$"): + compile(tree, "", "exec") + + def test_none_checks(self) -> None: + tests = [ + (ast.alias, "name", "import spam as SPAM"), + (ast.arg, "arg", "def spam(SPAM): spam"), + (ast.comprehension, "target", "[spam for SPAM in spam]"), + (ast.comprehension, "iter", "[spam for spam in SPAM]"), + (ast.keyword, "value", "spam(**SPAM)"), + (ast.match_case, "pattern", "match spam:\n case SPAM: spam"), + (ast.withitem, "context_expr", "with SPAM: spam"), + ] + for node, attr, source in tests: + self.assert_none_check(node, attr, source) + class ASTHelpers_Test(unittest.TestCase): maxDiff = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst new file mode 100644 index 00000000000000..3981dad7a49dfb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-09-11-19-51.gh-issue-105588.Y5ovpY.rst @@ -0,0 +1,2 @@ +Fix an issue that could result in crashes when compiling malformed +:mod:`ast` nodes. diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index cb312796f89e04..d4763ea260a5a2 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -601,6 +601,7 @@ def visitProduct(self, prod, name): args = [f.name for f in prod.fields] args.extend([a.name for a in prod.attributes]) self.emit("*out = %s(%s);" % (ast_func_name(name), self.buildArgs(args)), 1) + self.emit("if (*out == NULL) goto failed;", 1) self.emit("return 0;", 1) self.emit("failed:", 0) self.emit("Py_XDECREF(tmp);", 1) diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 84bce59e271471..1ffb8354e3a1b1 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -10834,6 +10834,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* Py_CLEAR(tmp); } *out = _PyAST_comprehension(target, iter, ifs, is_async, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11258,6 +11259,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } *out = _PyAST_arguments(posonlyargs, args, vararg, kwonlyargs, kw_defaults, kwarg, defaults, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11397,6 +11399,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) } *out = _PyAST_arg(arg, annotation, type_comment, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11519,6 +11522,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, } *out = _PyAST_keyword(arg, value, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11641,6 +11645,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* } *out = _PyAST_alias(name, asname, lineno, col_offset, end_lineno, end_col_offset, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11690,6 +11695,7 @@ obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, Py_CLEAR(tmp); } *out = _PyAST_withitem(context_expr, optional_vars, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); @@ -11778,6 +11784,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, Py_CLEAR(tmp); } *out = _PyAST_match_case(pattern, guard, body, arena); + if (*out == NULL) goto failed; return 0; failed: Py_XDECREF(tmp); From 25a64fd28aaaaf2d21fae23212a0554c24fc7b20 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 15 Jun 2023 16:34:42 -0700 Subject: [PATCH 066/446] GH-103124: Multiline statement support for pdb (GH-103125) --- Lib/pdb.py | 26 ++++++++++++++- Lib/test/test_pdb.py | 33 +++++++++++++++++-- ...-04-09-03-53-02.gh-issue-103124.JspiNN.rst | 1 + 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-04-09-03-53-02.gh-issue-103124.JspiNN.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 1af511788749db..3db3e6a5be1a7b 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -76,6 +76,7 @@ import dis import code import glob +import codeop import pprint import signal import inspect @@ -444,7 +445,30 @@ def default(self, line): locals = self.curframe_locals globals = self.curframe.f_globals try: - code = compile(line + '\n', '', 'single') + if (code := codeop.compile_command(line + '\n', '', 'single')) is None: + # Multi-line mode + buffer = line + continue_prompt = "... " + while (code := codeop.compile_command(buffer, '', 'single')) is None: + if self.use_rawinput: + try: + line = input(continue_prompt) + except (EOFError, KeyboardInterrupt): + self.lastcmd = "" + print('\n') + return + else: + self.stdout.write(continue_prompt) + self.stdout.flush() + line = self.stdin.readline() + if not len(line): + self.lastcmd = "" + self.stdout.write('\n') + self.stdout.flush() + return + else: + line = line.rstrip('\r\n') + buffer += '\n' + line save_stdout = sys.stdout save_stdin = sys.stdin save_displayhook = sys.displayhook diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 277400e152476f..a66953557e52dc 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -389,7 +389,7 @@ def test_pdb_breakpoints_preserved_across_interactive_sessions(): 1 breakpoint keep yes at ...test_pdb.py:... 2 breakpoint keep yes at ...test_pdb.py:... (Pdb) break pdb.find_function - Breakpoint 3 at ...pdb.py:97 + Breakpoint 3 at ...pdb.py:... (Pdb) break Num Type Disp Enb Where 1 breakpoint keep yes at ...test_pdb.py:... @@ -1589,6 +1589,32 @@ def test_pdb_next_command_subiterator(): (Pdb) continue """ +def test_pdb_multiline_statement(): + """Test for multiline statement + + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... pass + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'def f(x):', + ... ' return x * 2', + ... '', + ... 'f(2)', + ... 'c' + ... ]): + ... test_function() + > (3)test_function() + -> pass + (Pdb) def f(x): + ... return x * 2 + ... + (Pdb) f(2) + 4 + (Pdb) c + """ + + def test_pdb_issue_20766(): """Test for reference leaks when the SIGINT handler is set. @@ -2362,7 +2388,7 @@ def test_relative_imports_on_plain_module(self): def test_errors_in_command(self): commands = "\n".join([ - 'print(', + 'print(]', 'debug print(', 'debug doesnotexist', 'c', @@ -2371,7 +2397,8 @@ def test_errors_in_command(self): self.assertEqual(stdout.splitlines()[1:], [ '-> pass', - '(Pdb) *** SyntaxError: \'(\' was never closed', + "(Pdb) *** SyntaxError: closing parenthesis ']' does not match opening " + "parenthesis '('", '(Pdb) ENTERING RECURSIVE DEBUGGER', '*** SyntaxError: \'(\' was never closed', diff --git a/Misc/NEWS.d/next/Library/2023-04-09-03-53-02.gh-issue-103124.JspiNN.rst b/Misc/NEWS.d/next/Library/2023-04-09-03-53-02.gh-issue-103124.JspiNN.rst new file mode 100644 index 00000000000000..022524b369aa10 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-09-03-53-02.gh-issue-103124.JspiNN.rst @@ -0,0 +1 @@ +Added multiline statement support for :mod:`pdb` From 486b52a3158e0f64fc54efdfa34ed5437b3619f2 Mon Sep 17 00:00:00 2001 From: Alex Doe Date: Thu, 15 Jun 2023 18:04:57 -0600 Subject: [PATCH 067/446] bpo-44530: Document the change in MAKE_FUNCTION behavior (#93189) * bpo-44530: Document the change in MAKE_FUNCTION behavior Fixes dis module documentation for MAKE_FUNCTION due to https://github.com/python/cpython/commit/2f180ce2cb6e6a7e3c517495e0f4873d6aaf5f2f (bpo-44530, released as part of 3.11) removes the qualified name at TOS --- Doc/library/dis.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 714dbc38f168ae..c6f08affcbf2d0 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1431,12 +1431,15 @@ iterations of the loop. * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure - * the code associated with the function (at ``STACK[-2]``) - * the :term:`qualified name` of the function (at ``STACK[-1]``) + * the code associated with the function (at ``STACK[-1]``) .. versionchanged:: 3.10 Flag value ``0x04`` is a tuple of strings instead of dictionary + .. versionchanged:: 3.11 + Qualified name at ``STACK[-1]`` was removed. + + .. opcode:: BUILD_SLICE (argc) .. index:: pair: built-in function; slice From 1af8251d9ec2f18e131c19ccf776fb9ec132c7a8 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 16 Jun 2023 03:58:40 +0300 Subject: [PATCH 068/446] gh-105433: Add `pickle` tests for PEP695 (#105443) --- Lib/test/test_type_aliases.py | 69 +++++++++++++++++++++++++++++++++-- Lib/test/test_type_params.py | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index a3067e521e023e..b9b24448e83d8e 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -228,8 +228,69 @@ def test_module(self): self.assertEqual(mod_generics_cache.OldStyle.__module__, mod_generics_cache.__name__) + +# All these type aliases are used for pickling tests: +T = TypeVar('T') +type SimpleAlias = int +type RecursiveAlias = dict[str, RecursiveAlias] +type GenericAlias[X] = list[X] +type GenericAliasMultipleTypes[X, Y] = dict[X, Y] +type RecursiveGenericAlias[X] = dict[str, RecursiveAlias[X]] +type BoundGenericAlias[X: int] = set[X] +type ConstrainedGenericAlias[LongName: (str, bytes)] = list[LongName] +type AllTypesAlias[A, *B, **C] = Callable[C, A] | tuple[*B] + + +class TypeAliasPickleTest(unittest.TestCase): def test_pickling(self): - pickled = pickle.dumps(mod_generics_cache.Alias) - self.assertIs(pickle.loads(pickled), mod_generics_cache.Alias) - pickled = pickle.dumps(mod_generics_cache.OldStyle) - self.assertIs(pickle.loads(pickled), mod_generics_cache.OldStyle) + things_to_test = [ + SimpleAlias, + RecursiveAlias, + + GenericAlias, + GenericAlias[T], + GenericAlias[int], + + GenericAliasMultipleTypes, + GenericAliasMultipleTypes[str, T], + GenericAliasMultipleTypes[T, str], + GenericAliasMultipleTypes[int, str], + + RecursiveGenericAlias, + RecursiveGenericAlias[T], + RecursiveGenericAlias[int], + + BoundGenericAlias, + BoundGenericAlias[int], + BoundGenericAlias[T], + + ConstrainedGenericAlias, + ConstrainedGenericAlias[str], + ConstrainedGenericAlias[T], + + AllTypesAlias, + AllTypesAlias[int, str, T, [T, object]], + + # Other modules: + mod_generics_cache.Alias, + mod_generics_cache.OldStyle, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + type ClassLevel = str + + def test_pickling_local(self): + type A = int + things_to_test = [ + self.ClassLevel, + A, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + with self.assertRaises(pickle.PickleError): + pickle.dumps(thing, protocol=proto) diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 6475df6f5bba43..3026cc22476619 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -2,6 +2,7 @@ import textwrap import types import unittest +import pickle from test.support import requires_working_socket, check_syntax_error, run_code from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args @@ -855,3 +856,68 @@ def func[A](): ns = run_code(code) self.assertEqual(ns["func"].__type_params__, ()) + + + +# All these type aliases are used for pickling tests: +T = TypeVar('T') +def func1[X](x: X) -> X: ... +def func2[X, Y](x: X | Y) -> X | Y: ... +def func3[X, *Y, **Z](x: X, y: tuple[*Y], z: Z) -> X: ... +def func4[X: int, Y: (bytes, str)](x: X, y: Y) -> X | Y: ... + +class Class1[X]: ... +class Class2[X, Y]: ... +class Class3[X, *Y, **Z]: ... +class Class4[X: int, Y: (bytes, str)]: ... + + +class TypeParamsPickleTest(unittest.TestCase): + def test_pickling_functions(self): + things_to_test = [ + func1, + func2, + func3, + func4, + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + def test_pickling_classes(self): + things_to_test = [ + Class1, + Class1[int], + Class1[T], + + Class2, + Class2[int, T], + Class2[T, int], + Class2[int, str], + + Class3, + Class3[int, T, str, bytes, [float, object, T]], + + Class4, + Class4[int, bytes], + Class4[T, bytes], + Class4[int, T], + Class4[T, T], + ] + for thing in things_to_test: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + self.assertEqual(pickle.loads(pickled), thing) + + for klass in things_to_test: + real_class = getattr(klass, '__origin__', klass) + thing = klass() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(thing=thing, proto=proto): + pickled = pickle.dumps(thing, protocol=proto) + # These instances are not equal, + # but class check is good enough: + self.assertIsInstance(pickle.loads(pickled), real_class) From 0d0963737a0f4b7cadedfae7e8fd33ed18269289 Mon Sep 17 00:00:00 2001 From: chgnrdv <52372310+chgnrdv@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:10:59 +0300 Subject: [PATCH 069/446] Fix inaccuracies in "Assorted Topics" section of "Defining Extension Types" tutorial (#104969) --- Doc/extending/newtypes.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst index 6852a385f0c63c..7f8f8ddaaaccd6 100644 --- a/Doc/extending/newtypes.rst +++ b/Doc/extending/newtypes.rst @@ -168,7 +168,7 @@ representation of the instance for which it is called. Here is a simple example:: static PyObject * - newdatatype_repr(newdatatypeobject * obj) + newdatatype_repr(newdatatypeobject *obj) { return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); @@ -188,7 +188,7 @@ used instead. Here is a simple example:: static PyObject * - newdatatype_str(newdatatypeobject * obj) + newdatatype_str(newdatatypeobject *obj) { return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr->size); @@ -338,7 +338,7 @@ Here is an example:: PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '%.400s'", - tp->tp_name, name); + Py_TYPE(obj)->tp_name, name); return NULL; } @@ -379,7 +379,7 @@ Here is a sample implementation, for a datatype that is considered equal if the size of an internal pointer is equal:: static PyObject * - newdatatype_richcmp(PyObject *obj1, PyObject *obj2, int op) + newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int op) { PyObject *result; int c, size1, size2; @@ -478,7 +478,7 @@ This function takes three arguments: Here is a toy ``tp_call`` implementation:: static PyObject * - newdatatype_call(newdatatypeobject *self, PyObject *args, PyObject *kwds) + newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds) { PyObject *result; const char *arg1; From 0bffe1acd78069ea21f6b1347bec9cc9747342cb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 16 Jun 2023 10:41:47 +0200 Subject: [PATCH 070/446] gh-105844: Consistently use 'minor version' for X.Y versions (#105851) --- Doc/faq/general.rst | 4 ++-- Doc/install/index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index a9b2622e02ef3b..298ce111698a65 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -135,7 +135,7 @@ Python versions are numbered "A.B.C" or "A.B": See :pep:`6` for more information about bugfix releases. -Not all releases are bugfix releases. In the run-up to a new major release, a +Not all releases are bugfix releases. In the run-up to a new minor release, a series of development releases are made, denoted as alpha, beta, or release candidate. Alphas are early releases in which interfaces aren't yet finalized; it's not unexpected to see an interface change between two alpha releases. @@ -297,7 +297,7 @@ How stable is Python? Very stable. New, stable releases have been coming out roughly every 6 to 18 months since 1991, and this seems likely to continue. As of version 3.9, -Python will have a major new release every 12 months (:pep:`602`). +Python will have a minor new release every 12 months (:pep:`602`). The developers issue "bugfix" releases of older versions, so the stability of existing releases gradually improves. Bugfix releases, indicated by a third diff --git a/Doc/install/index.rst b/Doc/install/index.rst index ab581d785ef7f0..beb34f0cf21b22 100644 --- a/Doc/install/index.rst +++ b/Doc/install/index.rst @@ -696,7 +696,7 @@ is supplied to suppress this behaviour. So you could simply edit import sys sys.path.append('/www/python/') -However, if you reinstall the same major version of Python (perhaps when +However, if you reinstall the same minor version of Python (perhaps when upgrading from 2.2 to 2.2.2, for example) :file:`site.py` will be overwritten by the stock version. You'd have to remember that it was modified and save a copy before doing the installation. From 101d5ec7d7fe122fa81a377c8ab8b562d1add9ee Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 16 Jun 2023 14:04:34 +0300 Subject: [PATCH 071/446] CI: Remove docs build from Azure Pipelines (#105823) --- .azure-pipelines/ci.yml | 14 --------- .azure-pipelines/docs-steps.yml | 47 ---------------------------- .azure-pipelines/pr.yml | 12 ------- .azure-pipelines/prebuild-checks.yml | 12 ------- 4 files changed, 85 deletions(-) delete mode 100644 .azure-pipelines/docs-steps.yml diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index fb4a2218ddd8d8..63252a76abb69f 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -14,20 +14,6 @@ jobs: - template: ./prebuild-checks.yml -- job: Docs_PR - displayName: Docs PR - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true')) - - pool: - vmImage: ubuntu-22.04 - - steps: - - template: ./docs-steps.yml - parameters: - upload: true - - - job: macOS_CI_Tests displayName: macOS CI Tests dependsOn: Prebuild diff --git a/.azure-pipelines/docs-steps.yml b/.azure-pipelines/docs-steps.yml deleted file mode 100644 index 647daff7a033a8..00000000000000 --- a/.azure-pipelines/docs-steps.yml +++ /dev/null @@ -1,47 +0,0 @@ -parameters: - latex: false - upload: false - -steps: -- checkout: self - clean: true - fetchDepth: 5 - -- task: UsePythonVersion@0 - displayName: 'Use Python 3.6 or later' - inputs: - versionSpec: '>=3.6' - -- script: python -m pip install -r requirements.txt - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Install build dependencies' - -- ${{ if ne(parameters.latex, 'true') }}: - - script: make check html PYTHON=python - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Build documentation' - -- ${{ if eq(parameters.latex, 'true') }}: - - script: sudo apt-get update && sudo apt-get install -qy --force-yes texlive-full - displayName: 'Install LaTeX' - - - script: make dist PYTHON=python SPHINXBUILD='python -m sphinx' BLURB='python -m blurb' - workingDirectory: '$(build.sourcesDirectory)/Doc' - displayName: 'Build documentation' - -- ${{ if eq(parameters.upload, 'true') }}: - - task: PublishBuildArtifacts@1 - displayName: 'Publish docs' - - inputs: - PathToPublish: '$(build.sourcesDirectory)/Doc/build' - ArtifactName: docs - publishLocation: Container - - - ${{ if eq(parameters.latex, 'true') }}: - - task: PublishBuildArtifacts@1 - displayName: 'Publish dist' - inputs: - PathToPublish: '$(build.sourcesDirectory)/Doc/dist' - ArtifactName: docs_dist - publishLocation: Container diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index b822d58806b9a6..939c9b4249a3c2 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -14,18 +14,6 @@ jobs: - template: ./prebuild-checks.yml -- job: Docs_PR - displayName: Docs PR - dependsOn: Prebuild - condition: and(succeeded(), eq(dependencies.Prebuild.outputs['docs.run'], 'true')) - - pool: - vmImage: ubuntu-22.04 - - steps: - - template: ./docs-steps.yml - - - job: macOS_PR_Tests displayName: macOS PR Tests dependsOn: Prebuild diff --git a/.azure-pipelines/prebuild-checks.yml b/.azure-pipelines/prebuild-checks.yml index 30ff642d1267a1..2c6460d2386735 100644 --- a/.azure-pipelines/prebuild-checks.yml +++ b/.azure-pipelines/prebuild-checks.yml @@ -11,18 +11,6 @@ steps: displayName: Fetch comparison tree condition: and(succeeded(), variables['System.PullRequest.TargetBranch']) -- script: | - if ! git diff --name-only $(diffTarget) | grep -qE '(\.rst$|^Doc|^Misc)' - then - echo "No docs were updated: docs.run=false" - echo "##vso[task.setvariable variable=run;isOutput=true]false" - else - echo "Docs were updated: docs.run=true" - echo "##vso[task.setvariable variable=run;isOutput=true]true" - fi - displayName: Detect documentation changes - name: docs - - script: | if ! git diff --name-only $(diffTarget) | grep -qvE '(\.rst$|^Doc|^Misc)' then From 70c075c194d3739ae10ce76265f05fa82ed46487 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 16 Jun 2023 16:47:55 +0100 Subject: [PATCH 072/446] gh-105834: Add tests for calling `issubclass()` between two protocols (#105835) Some parts of the implementation of `typing.Protocol` had poor test coverage --- Lib/test/test_typing.py | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3eb0fcad69e5e5..ad67568770970f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2759,6 +2759,80 @@ def x(self): ... with self.assertRaisesRegex(TypeError, only_classes_allowed): issubclass(1, BadPG) + def test_implicit_issubclass_between_two_protocols(self): + @runtime_checkable + class CallableMembersProto(Protocol): + def meth(self): ... + + # All the below protocols should be considered "subclasses" + # of CallableMembersProto at runtime, + # even though none of them explicitly subclass CallableMembersProto + + class IdenticalProto(Protocol): + def meth(self): ... + + class SupersetProto(Protocol): + def meth(self): ... + def meth2(self): ... + + class NonCallableMembersProto(Protocol): + meth: Callable[[], None] + + class NonCallableMembersSupersetProto(Protocol): + meth: Callable[[], None] + meth2: Callable[[str, int], bool] + + class MixedMembersProto1(Protocol): + meth: Callable[[], None] + def meth2(self): ... + + class MixedMembersProto2(Protocol): + def meth(self): ... + meth2: Callable[[str, int], bool] + + for proto in ( + IdenticalProto, SupersetProto, NonCallableMembersProto, + NonCallableMembersSupersetProto, MixedMembersProto1, MixedMembersProto2 + ): + with self.subTest(proto=proto.__name__): + self.assertIsSubclass(proto, CallableMembersProto) + + # These two shouldn't be considered subclasses of CallableMembersProto, however, + # since they don't have the `meth` protocol member + + class EmptyProtocol(Protocol): ... + class UnrelatedProtocol(Protocol): + def wut(self): ... + + self.assertNotIsSubclass(EmptyProtocol, CallableMembersProto) + self.assertNotIsSubclass(UnrelatedProtocol, CallableMembersProto) + + # These aren't protocols at all (despite having annotations), + # so they should only be considered subclasses of CallableMembersProto + # if they *actually have an attribute* matching the `meth` member + # (just having an annotation is insufficient) + + class AnnotatedButNotAProtocol: + meth: Callable[[], None] + + class NotAProtocolButAnImplicitSubclass: + def meth(self): pass + + class NotAProtocolButAnImplicitSubclass2: + meth: Callable[[], None] + def meth(self): pass + + class NotAProtocolButAnImplicitSubclass3: + meth: Callable[[], None] + meth2: Callable[[int, str], bool] + def meth(self): pass + def meth(self, x, y): return True + + self.assertNotIsSubclass(AnnotatedButNotAProtocol, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass2, CallableMembersProto) + self.assertIsSubclass(NotAProtocolButAnImplicitSubclass3, CallableMembersProto) + def test_isinstance_checks_not_at_whim_of_gc(self): self.addCleanup(gc.enable) gc.disable() From 957a974d4fc1575787e4a29a399a47520d6df6d3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 16 Jun 2023 09:31:23 -0700 Subject: [PATCH 073/446] gh-104799: PEP 695 backward compatibility for ast.unparse (#105846) --- Lib/ast.py | 6 +- Lib/test/test_unparse.py | 74 ++++++++++++++++++- ...-06-15-18-11-47.gh-issue-104799.BcLzbP.rst | 3 + 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst diff --git a/Lib/ast.py b/Lib/ast.py index 226910ecac0b4a..a307f3ecd06175 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1051,7 +1051,8 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - self._type_params_helper(node.type_params) + if hasattr(node, "type_params"): + self._type_params_helper(node.type_params) with self.delimit_if("(", ")", condition = node.bases or node.keywords): comma = False for e in node.bases: @@ -1083,7 +1084,8 @@ def _function_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) - self._type_params_helper(node.type_params) + if hasattr(node, "type_params"): + self._type_params_helper(node.type_params) with self.delimit("(", ")"): self.traverse(node.args) if node.returns: diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 88c7c3a0af8771..41a6318d1499b4 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -1,4 +1,4 @@ -"""Tests for the unparse.py script in the Tools/parser directory.""" +"""Tests for ast.unparse.""" import unittest import test.support @@ -625,6 +625,78 @@ def test_star_expr_assign_target_multiple(self): self.check_src_roundtrip("a, b = [c, d] = e, f = g") +class ManualASTCreationTestCase(unittest.TestCase): + """Test that AST nodes created without a type_params field unparse correctly.""" + + def test_class(self): + node = ast.ClassDef(name="X", bases=[], keywords=[], body=[ast.Pass()], decorator_list=[]) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "class X:\n pass") + + def test_class_with_type_params(self): + node = ast.ClassDef(name="X", bases=[], keywords=[], body=[ast.Pass()], decorator_list=[], + type_params=[ast.TypeVar("T")]) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "class X[T]:\n pass") + + def test_function(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f():\n pass") + + def test_function_with_type_params(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T")], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f[T]():\n pass") + + def test_function_with_type_params_and_bound(self): + node = ast.FunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T", bound=ast.Name("int"))], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "def f[T: int]():\n pass") + + def test_async_function(self): + node = ast.AsyncFunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "async def f():\n pass") + + def test_async_function_with_type_params(self): + node = ast.AsyncFunctionDef( + name="f", + args=ast.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), + body=[ast.Pass()], + decorator_list=[], + returns=None, + type_params=[ast.TypeVar("T")], + ) + ast.fix_missing_locations(node) + self.assertEqual(ast.unparse(node), "async def f[T]():\n pass") + class DirectoryTestCase(ASTTestCase): """Test roundtrip behaviour on all files in Lib and Lib/test.""" diff --git a/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst b/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst new file mode 100644 index 00000000000000..d0dbff4f1553e2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-15-18-11-47.gh-issue-104799.BcLzbP.rst @@ -0,0 +1,3 @@ +Enable :func:`ast.unparse` to unparse function and class definitions created +without the new ``type_params`` field from :pep:`695`. Patch by Jelle +Zijlstra. From b356a4749acb3e6f8c50e8abeb7b2d2b267738d7 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 16 Jun 2023 12:36:59 -0500 Subject: [PATCH 074/446] gh-105678: document SET_FUNCTION_ATTRIBUTE (#105843) --- Doc/library/dis.rst | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c6f08affcbf2d0..1caf3c097e1dce 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1421,23 +1421,34 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: MAKE_FUNCTION (flags) +.. opcode:: MAKE_FUNCTION - Pushes a new function object on the stack. From bottom to top, the consumed - stack must consist of values if the argument carries a specified flag value + Pushes a new function object on the stack built from the code object at ``STACK[1]``. + + .. versionchanged:: 3.10 + Flag value ``0x04`` is a tuple of strings instead of dictionary + + .. versionchanged:: 3.11 + Qualified name at ``STACK[-1]`` was removed. + + .. versionchanged:: 3.13 + Extra function attributes on the stack, signaled by oparg flags, were + removed. They now use :opcode:`SET_FUNCTION_ATTRIBUTE`. + + +.. opcode:: SET_FUNCTION_ATTRIBUTE (flag) + + Sets an attribute on a function object. Expects the function at ``STACK[-1]`` + and the attribute value to set at ``STACK[-2]``; consumes both and leaves the + function at ``STACK[-1]``. The flag determines which attribute to set: * ``0x01`` a tuple of default values for positional-only and positional-or-keyword parameters in positional order * ``0x02`` a dictionary of keyword-only parameters' default values * ``0x04`` a tuple of strings containing parameters' annotations * ``0x08`` a tuple containing cells for free variables, making a closure - * the code associated with the function (at ``STACK[-1]``) - - .. versionchanged:: 3.10 - Flag value ``0x04`` is a tuple of strings instead of dictionary - .. versionchanged:: 3.11 - Qualified name at ``STACK[-1]`` was removed. + .. versionadded:: 3.13 .. opcode:: BUILD_SLICE (argc) From 2beab5bdef5fa2a00a59371e6137f769586b7404 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 16 Jun 2023 11:01:15 -0700 Subject: [PATCH 075/446] GH-105840: Fix assertion failures when specializing calls with too many __defaults__ (GH-105847) --- Lib/test/test_opcache.py | 29 +++++++++++++++++++ ...-06-15-22-11-43.gh-issue-105840.Fum_g_.rst | 2 ++ Python/specialize.c | 4 +-- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 57fed5d09fd7b8..5281eb77c02d1b 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -452,6 +452,35 @@ def f(): self.assertFalse(f()) +class TestCallCache(unittest.TestCase): + def test_too_many_defaults_0(self): + def f(): + pass + + f.__defaults__ = (None,) + for _ in range(1025): + f() + + def test_too_many_defaults_1(self): + def f(x): + pass + + f.__defaults__ = (None, None) + for _ in range(1025): + f(None) + f() + + def test_too_many_defaults_2(self): + def f(x, y): + pass + + f.__defaults__ = (None, None, None) + for _ in range(1025): + f(None, None) + f(None) + f() + + if __name__ == "__main__": import unittest unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst new file mode 100644 index 00000000000000..5225031292e6c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst @@ -0,0 +1,2 @@ +Fix possible crashes when specializing function calls with too many +``__defaults__``. diff --git a/Python/specialize.c b/Python/specialize.c index cff414a01d0a37..44b14c5952315f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1647,9 +1647,9 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, } int argcount = code->co_argcount; int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); - assert(defcount <= argcount); int min_args = argcount-defcount; - if (nargs > argcount || nargs < min_args) { + // GH-105840: min_args is negative when somebody sets too many __defaults__! + if (min_args < 0 || nargs > argcount || nargs < min_args) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } From 34e93d3998bab8acd651c50724eb1977f4860a08 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 16 Jun 2023 21:00:37 +0200 Subject: [PATCH 076/446] CI: Bump macOS build to use OpenSSL v3.0 (#105538) --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77c2088c714497..4760c07a6d9cbb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -232,7 +232,7 @@ jobs: path: config.cache key: ${{ github.job }}-${{ runner.os }}-${{ needs.check_source.outputs.config_hash }} - name: Install Homebrew dependencies - run: brew install pkg-config openssl@1.1 xz gdbm tcl-tk + run: brew install pkg-config openssl@3.0 xz gdbm tcl-tk - name: Configure CPython run: | GDBM_CFLAGS="-I$(brew --prefix gdbm)/include" \ @@ -241,7 +241,7 @@ jobs: --config-cache \ --with-pydebug \ --prefix=/opt/python-dev \ - --with-openssl="$(brew --prefix openssl@1.1)" + --with-openssl="$(brew --prefix openssl@3.0)" - name: Build CPython run: make -j4 - name: Display build info From 14d01262dad02579b3dffe5965f640ce21c38896 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 17 Jun 2023 17:00:16 +0100 Subject: [PATCH 077/446] gh-105481: remove HAS_ARG, HAS_CONST, IS_JUMP_OPCODE, IS_PSEUDO_OPCODE and replace by their new versions (#105865) --- Doc/library/dis.rst | 6 ++++ Include/internal/pycore_opcode.h | 13 -------- Include/internal/pycore_opcode_utils.h | 26 +--------------- Include/opcode.h | 19 ------------ Lib/test/test__opcode.py | 10 ++----- ...-06-17-12-13-57.gh-issue-105481.KgBH5w.rst | 4 +++ Modules/_opcode.c | 22 ++++---------- Python/assemble.c | 3 +- Python/ceval.c | 5 ++-- Python/compile.c | 17 ++++------- Python/flowgraph.c | 21 +++++++------ Tools/build/generate_opcode_h.py | 30 ------------------- 12 files changed, 38 insertions(+), 138 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-17-12-13-57.gh-issue-105481.KgBH5w.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 1caf3c097e1dce..39d43578faf3c3 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -318,6 +318,12 @@ operation is being performed, so the intermediate analysis object isn't useful: .. versionchanged:: 3.8 Added *jump* parameter. + .. versionchanged:: 3.13 + If ``oparg`` is omitted (or ``None``), the stack effect is now returned + for ``oparg=0``. Previously this was an error for opcodes that use their + arg. It is also no longer an error to pass an integer ``oparg`` when + the ``opcode`` does not use it; the ``oparg`` in this case is ignored. + .. _bytecodes: diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index d680039e5eed96..5935823b7e24ad 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -12,24 +12,11 @@ extern "C" { #include "opcode.h" -extern const uint32_t _PyOpcode_Jump[9]; - extern const uint8_t _PyOpcode_Caches[256]; extern const uint8_t _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_TABLES -const uint32_t _PyOpcode_Jump[9] = { - 0U, - 0U, - 536870912U, - 135020544U, - 4163U, - 0U, - 0U, - 0U, - 48U, -}; const uint8_t _PyOpcode_Caches[256] = { [BINARY_SUBSCR] = 1, diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h index d80b3c1c20b149..50ff2af38d2cbe 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -15,10 +15,7 @@ extern "C" { #define IS_WITHIN_OPCODE_RANGE(opcode) \ (((opcode) >= 0 && (opcode) <= MAX_REAL_OPCODE) || \ - IS_PSEUDO_OPCODE(opcode)) - -#define IS_JUMP_OPCODE(opcode) \ - is_bit_set_in_table(_PyOpcode_Jump, opcode) + IS_PSEUDO_INSTR(opcode)) #define IS_BLOCK_PUSH_OPCODE(opcode) \ ((opcode) == SETUP_FINALLY || \ @@ -55,27 +52,6 @@ extern "C" { (opcode) == RAISE_VARARGS || \ (opcode) == RERAISE) -#define LOG_BITS_PER_INT 5 -#define MASK_LOW_LOG_BITS 31 - -static inline int -is_bit_set_in_table(const uint32_t *table, int bitindex) { - /* Is the relevant bit set in the relevant word? */ - /* 512 bits fit into 9 32-bits words. - * Word is indexed by (bitindex>>ln(size of int in bits)). - * Bit within word is the low bits of bitindex. - */ - if (bitindex >= 0 && bitindex < 512) { - uint32_t word = table[bitindex >> LOG_BITS_PER_INT]; - return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1; - } - else { - return 0; - } -} - -#undef LOG_BITS_PER_INT -#undef MASK_LOW_LOG_BITS /* Flags used in the oparg for MAKE_FUNCTION */ #define MAKE_FUNCTION_DEFAULTS 0x01 diff --git a/Include/opcode.h b/Include/opcode.h index c6ffaee3522142..43a18065cf08c2 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -50,7 +50,6 @@ extern "C" { #define SETUP_ANNOTATIONS 85 #define LOAD_LOCALS 87 #define POP_EXCEPT 89 -#define HAVE_ARGUMENT 90 #define STORE_NAME 90 #define DELETE_NAME 91 #define UNPACK_SEQUENCE 92 @@ -219,22 +218,6 @@ extern "C" { #define UNPACK_SEQUENCE_TWO_TUPLE 160 #define SEND_GEN 161 -#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ - || ((op) == JUMP) \ - || ((op) == JUMP_NO_INTERRUPT) \ - || ((op) == LOAD_METHOD) \ - || ((op) == LOAD_SUPER_METHOD) \ - || ((op) == LOAD_ZERO_SUPER_METHOD) \ - || ((op) == LOAD_ZERO_SUPER_ATTR) \ - || ((op) == STORE_FAST_MAYBE_NULL) \ - ) - -#define HAS_CONST(op) (false\ - || ((op) == LOAD_CONST) \ - || ((op) == RETURN_CONST) \ - || ((op) == KW_NAMES) \ - ) - #define NB_ADD 0 #define NB_AND 1 #define NB_FLOOR_DIVIDE 2 @@ -265,8 +248,6 @@ extern "C" { /* Defined in Lib/opcode.py */ #define ENABLE_SPECIALIZATION 1 -#define IS_PSEUDO_OPCODE(op) (((op) >= MIN_PSEUDO_OPCODE) && ((op) <= MAX_PSEUDO_OPCODE)) - #ifdef __cplusplus } #endif diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 7640c6fb57d4f3..3e084928844d2f 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -15,20 +15,14 @@ def test_stack_effect(self): self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) self.assertRaises(ValueError, stack_effect, 30000) - self.assertRaises(ValueError, stack_effect, dis.opmap['BUILD_SLICE']) - self.assertRaises(ValueError, stack_effect, dis.opmap['POP_TOP'], 0) # All defined opcodes has_arg = dis.hasarg for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): if code >= opcode.MIN_INSTRUMENTED_OPCODE: continue with self.subTest(opname=name): - if code not in has_arg: - stack_effect(code) - self.assertRaises(ValueError, stack_effect, code, 0) - else: - stack_effect(code, 0) - self.assertRaises(ValueError, stack_effect, code) + stack_effect(code) + stack_effect(code, 0) # All not defined opcodes for code in set(range(256)) - set(dis.opmap.values()): with self.subTest(opcode=code): diff --git a/Misc/NEWS.d/next/Library/2023-06-17-12-13-57.gh-issue-105481.KgBH5w.rst b/Misc/NEWS.d/next/Library/2023-06-17-12-13-57.gh-issue-105481.KgBH5w.rst new file mode 100644 index 00000000000000..11084ef956dcf3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-17-12-13-57.gh-issue-105481.KgBH5w.rst @@ -0,0 +1,4 @@ +:func:`~dis.stack_effect` no longer raises an exception if an ``oparg`` is +provided for an ``opcode`` that doesn't use its arg, or when it is not +provided for an ``opcode`` that does use it. In the latter case, the stack +effect is returned for ``oparg=0``. diff --git a/Modules/_opcode.c b/Modules/_opcode.c index b70d426fa29bc0..3c0fce48770ac4 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -27,25 +27,16 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg, PyObject *jump) /*[clinic end generated code: output=64a18f2ead954dbb input=461c9d4a44851898]*/ { - int effect; int oparg_int = 0; int jump_int; - if (HAS_ARG(opcode)) { - if (oparg == Py_None) { - PyErr_SetString(PyExc_ValueError, - "stack_effect: opcode requires oparg but oparg was not specified"); - return -1; - } + + if (oparg != Py_None) { oparg_int = (int)PyLong_AsLong(oparg); if ((oparg_int == -1) && PyErr_Occurred()) { return -1; } } - else if (oparg != Py_None) { - PyErr_SetString(PyExc_ValueError, - "stack_effect: opcode does not permit oparg but oparg was specified"); - return -1; - } + if (jump == Py_None) { jump_int = -1; } @@ -60,11 +51,10 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg, "stack_effect: jump must be False, True or None"); return -1; } - effect = PyCompile_OpcodeStackEffectWithJump(opcode, oparg_int, jump_int); + int effect = PyCompile_OpcodeStackEffectWithJump(opcode, oparg_int, jump_int); if (effect == PY_INVALID_STACK_EFFECT) { - PyErr_SetString(PyExc_ValueError, - "invalid opcode or oparg"); - return -1; + PyErr_SetString(PyExc_ValueError, "invalid opcode or oparg"); + return -1; } return effect; } diff --git a/Python/assemble.c b/Python/assemble.c index 85c6fe76f45ad2..d6213f89e7bf75 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -339,10 +339,9 @@ static void write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen) { int opcode = instr->i_opcode; - assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode)); assert(!IS_PSEUDO_INSTR(opcode)); int oparg = instr->i_oparg; - assert(HAS_ARG(opcode) || oparg == 0); + assert(OPCODE_HAS_ARG(opcode) || oparg == 0); int caches = _PyOpcode_Caches[opcode]; switch (ilen - caches) { case 4: diff --git a/Python/ceval.c b/Python/ceval.c index b628190fcd57ac..b1ac4de3f625da 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -29,6 +29,7 @@ #include "pycore_frame.h" #include "frameobject.h" // _PyInterpreterFrame_GetLine #include "opcode.h" +#include "opcode_metadata.h" #include "pydtrace.h" #include "setobject.h" #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX @@ -141,7 +142,7 @@ lltrace_instruction(_PyInterpreterFrame *frame, const char *opname = _PyOpcode_OpName[opcode]; assert(opname != NULL); int offset = (int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame))); - if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) { + if (OPCODE_HAS_ARG((int)_PyOpcode_Deopt[opcode])) { printf("%d: %s %d\n", offset * 2, opname, oparg); } else { @@ -882,7 +883,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #if USE_COMPUTED_GOTOS _unknown_opcode: #else - EXTRA_CASES // From opcode.h, a 'case' for each unused opcode + EXTRA_CASES // From pycore_opcode.h, a 'case' for each unused opcode #endif /* Tell C compilers not to hold the opcode variable in the loop. next_instr points the current instruction without TARGET(). */ diff --git a/Python/compile.c b/Python/compile.c index afb7b7dd3932eb..cfa945ba7603bb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -134,9 +134,8 @@ enum { int _PyCompile_InstrSize(int opcode, int oparg) { - assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode)); assert(!IS_PSEUDO_INSTR(opcode)); - assert(HAS_ARG(opcode) || oparg == 0); + assert(OPCODE_HAS_ARG(opcode) || oparg == 0); int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); int caches = _PyOpcode_Caches[opcode]; return extended_args + 1 + caches; @@ -248,15 +247,9 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) { static int instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) { - /* compare old and new opcode macros - use ! to compare as bools. */ - assert(!HAS_ARG(opcode) == !OPCODE_HAS_ARG(opcode)); - assert(!HAS_CONST(opcode) == !OPCODE_HAS_CONST(opcode)); - assert(!OPCODE_HAS_JUMP(opcode) == !OPCODE_HAS_JUMP(opcode)); - assert(0 <= opcode && opcode <= MAX_OPCODE); - assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode)); assert(IS_WITHIN_OPCODE_RANGE(opcode)); - assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(OPCODE_HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); int idx = instr_sequence_next_inst(seq); @@ -874,7 +867,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { - assert(!HAS_ARG(opcode)); + assert(!OPCODE_HAS_ARG(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); return instr_sequence_addop(seq, opcode, 0, loc); } @@ -1151,7 +1144,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_N(C, LOC, OP, O, TYPE) { \ - assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ + assert(!OPCODE_HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ @@ -7798,7 +7791,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq) goto error; } int oparg; - if (HAS_ARG(opcode)) { + if (OPCODE_HAS_ARG(opcode)) { oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); if (PyErr_Occurred()) { goto error; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index de5c5e7ecc38d6..39f780e60220a1 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -45,14 +45,13 @@ is_block_push(cfg_instr *i) static inline int is_jump(cfg_instr *i) { - assert(!OPCODE_HAS_JUMP(i->i_opcode) == !IS_JUMP_OPCODE(i->i_opcode)); return OPCODE_HAS_JUMP(i->i_opcode); } /* One arg*/ #define INSTR_SET_OP1(I, OP, ARG) \ do { \ - assert(HAS_ARG(OP)); \ + assert(OPCODE_HAS_ARG(OP)); \ _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ @@ -61,7 +60,7 @@ is_jump(cfg_instr *i) /* No args*/ #define INSTR_SET_OP0(I, OP) \ do { \ - assert(!HAS_ARG(OP)); \ + assert(!OPCODE_HAS_ARG(OP)); \ _PyCfgInstruction *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ @@ -111,7 +110,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); - assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(OPCODE_HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); assert(0 <= oparg && oparg < (1 << 30)); int off = basicblock_next_instr(b); @@ -193,7 +192,7 @@ dump_instr(cfg_instr *i) char arg[128]; *arg = '\0'; - if (HAS_ARG(i->i_opcode)) { + if (OPCODE_HAS_ARG(i->i_opcode)) { sprintf(arg, "arg: %d ", i->i_oparg); } if (HAS_TARGET(i->i_opcode)) { @@ -1108,7 +1107,7 @@ static PyObject* get_const_value(int opcode, int oparg, PyObject *co_consts) { PyObject *constant = NULL; - assert(HAS_CONST(opcode)); + assert(OPCODE_HAS_CONST(opcode)); if (opcode == LOAD_CONST) { constant = PyList_GET_ITEM(co_consts, oparg); } @@ -1139,7 +1138,7 @@ fold_tuple_on_constants(PyObject *const_cache, assert(inst[n].i_oparg == n); for (int i = 0; i < n; i++) { - if (!HAS_CONST(inst[i].i_opcode)) { + if (!OPCODE_HAS_CONST(inst[i].i_opcode)) { return SUCCESS; } } @@ -1542,8 +1541,8 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) } break; default: - /* All HAS_CONST opcodes should be handled with LOAD_CONST */ - assert (!HAS_CONST(inst->i_opcode)); + /* All OPCODE_HAS_CONST opcodes should be handled with LOAD_CONST */ + assert (!OPCODE_HAS_CONST(inst->i_opcode)); } } @@ -1793,7 +1792,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts) /* mark used consts */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - if (HAS_CONST(b->b_instr[i].i_opcode)) { + if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) { int index = b->b_instr[i].i_oparg; index_map[index] = index; } @@ -1846,7 +1845,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - if (HAS_CONST(b->b_instr[i].i_opcode)) { + if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) { int index = b->b_instr[i].i_oparg; assert(reverse_index_map[index] >= 0); assert(reverse_index_map[index] < n_used_consts); diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 5be981005725bf..ec9fdae56128c0 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -21,8 +21,6 @@ footer = """ -#define IS_PSEUDO_OPCODE(op) (((op) >= MIN_PSEUDO_OPCODE) && ((op) <= MAX_PSEUDO_OPCODE)) - #ifdef __cplusplus } #endif @@ -68,16 +66,6 @@ UINT32_MASK = (1<<32)-1 -def write_int_array_from_ops(name, ops, out): - bits = 0 - for op in ops: - bits |= 1<>= 32 - assert bits == 0 - out.write(f"}};\n") def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h', @@ -100,7 +88,6 @@ def main(opcode_py, outfile='Include/opcode.h', _pseudo_ops = opcode['_pseudo_ops'] ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"] - HAVE_ARGUMENT = opcode["HAVE_ARGUMENT"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"] MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"] @@ -130,8 +117,6 @@ def main(opcode_py, outfile='Include/opcode.h', for name in opname: if name in opmap: op = opmap[name] - if op == HAVE_ARGUMENT: - fobj.write(DEFINE.format("HAVE_ARGUMENT", HAVE_ARGUMENT)) if op == MIN_PSEUDO_OPCODE: fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE)) if op == MIN_INSTRUMENTED_OPCODE: @@ -146,11 +131,9 @@ def main(opcode_py, outfile='Include/opcode.h', for name, op in specialized_opmap.items(): fobj.write(DEFINE.format(name, op)) - iobj.write("\nextern const uint32_t _PyOpcode_Jump[9];\n") iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") iobj.write("\n#ifdef NEED_OPCODE_TABLES\n") - write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj) iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n") for i, entries in enumerate(opcode["_inline_cache_entries"]): @@ -171,19 +154,6 @@ def main(opcode_py, outfile='Include/opcode.h', iobj.write("};\n") iobj.write("#endif // NEED_OPCODE_TABLES\n") - fobj.write("\n") - fobj.write("#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\\") - for op in _pseudo_ops: - if opmap[op] in hasarg: - fobj.write(f"\n || ((op) == {op}) \\") - fobj.write("\n )\n") - - fobj.write("\n") - fobj.write("#define HAS_CONST(op) (false\\") - for op in hasconst: - fobj.write(f"\n || ((op) == {opname[op]}) \\") - fobj.write("\n )\n") - fobj.write("\n") for i, (op, _) in enumerate(opcode["_nb_ops"]): fobj.write(DEFINE.format(op, i)) From dba72175116373c1d15e25d84c88b516daf9f5c4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 18 Jun 2023 12:25:23 +0200 Subject: [PATCH 078/446] gh-105844: Use devguide terminology to denote versions (#105882) --- Doc/faq/general.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/general.rst b/Doc/faq/general.rst index 298ce111698a65..8727332594bda6 100644 --- a/Doc/faq/general.rst +++ b/Doc/faq/general.rst @@ -135,7 +135,7 @@ Python versions are numbered "A.B.C" or "A.B": See :pep:`6` for more information about bugfix releases. -Not all releases are bugfix releases. In the run-up to a new minor release, a +Not all releases are bugfix releases. In the run-up to a new feature release, a series of development releases are made, denoted as alpha, beta, or release candidate. Alphas are early releases in which interfaces aren't yet finalized; it's not unexpected to see an interface change between two alpha releases. @@ -297,9 +297,9 @@ How stable is Python? Very stable. New, stable releases have been coming out roughly every 6 to 18 months since 1991, and this seems likely to continue. As of version 3.9, -Python will have a minor new release every 12 months (:pep:`602`). +Python will have a new feature release every 12 months (:pep:`602`). -The developers issue "bugfix" releases of older versions, so the stability of +The developers issue bugfix releases of older versions, so the stability of existing releases gradually improves. Bugfix releases, indicated by a third component of the version number (e.g. 3.5.3, 3.6.2), are managed for stability; only fixes for known problems are included in a bugfix release, and it's From bc07c8f096791d678ca5c1e3486cb9648f7a027b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 18 Jun 2023 14:52:05 +0300 Subject: [PATCH 079/446] Docs: move sphinx-lint to pre-commit (#105750) --- .github/workflows/reusable-docs.yml | 4 ---- .pre-commit-config.yaml | 8 ++++++++ Doc/Makefile | 8 +++----- Doc/constraints.txt | 4 ---- Doc/requirements.txt | 1 - 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index 8a271e867c8b4d..c5a15a10866e27 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -28,8 +28,6 @@ jobs: cache-dependency-path: 'Doc/requirements.txt' - name: 'Install build dependencies' run: make -C Doc/ venv - - name: 'Check documentation' - run: make -C Doc/ check - name: 'Build HTML documentation' run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html @@ -59,8 +57,6 @@ jobs: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 # This build doesn't use problem matchers or check annotations - # It also does not run 'make check', as sphinx-lint is not installed into the - # environment. build_doc_oldest_supported_sphinx: name: 'Docs (Oldest Sphinx)' runs-on: ubuntu-latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 808622f19a3dbf..464bcde6e98424 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,3 +5,11 @@ repos: - id: check-yaml - id: trailing-whitespace types_or: [c, python, rst] + + - repo: https://github.com/sphinx-contrib/sphinx-lint + rev: v0.6.7 + hooks: + - id: sphinx-lint + args: [--enable=default-role] + files: ^Doc/ + types: [rst] diff --git a/Doc/Makefile b/Doc/Makefile index c11ea6ce03e8a4..22691895068fea 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -216,11 +216,9 @@ dist: rm dist/python-$(DISTVERSION)-docs-texinfo.tar .PHONY: check -check: - # Check the docs and NEWS files with sphinx-lint. - # Ignore the tools and venv dirs and check that the default role is not used. - $(SPHINXLINT) -i tools -i $(VENVDIR) --enable default-role - $(SPHINXLINT) --enable default-role ../Misc/NEWS.d/next/ +check: venv + $(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit + $(VENVDIR)/bin/python3 -m pre_commit run --all-files .PHONY: serve serve: diff --git a/Doc/constraints.txt b/Doc/constraints.txt index 66c748eb092d83..54888eaab242ee 100644 --- a/Doc/constraints.txt +++ b/Doc/constraints.txt @@ -23,7 +23,3 @@ sphinxcontrib-serializinghtml<1.2 # Direct dependencies of Jinja2 (Jinja is a dependency of Sphinx, see above) MarkupSafe<2.2 - -# Direct dependencies of sphinx-lint -polib<1.3 -regex<2024 diff --git a/Doc/requirements.txt b/Doc/requirements.txt index d3fa6ce6dabc60..bde509febf5bde 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -11,7 +11,6 @@ sphinx==6.2.0 blurb -sphinx-lint==0.6.7 sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need From 6849acb3feacda63ee43f1dc9be28fac1075ca7d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 19 Jun 2023 00:29:08 +0200 Subject: [PATCH 080/446] gh-105875: Require SQLite 3.15.2 or newer (#105876) SQLite 3.15.2 was released 2016-11-28. --- Doc/library/sqlite3.rst | 5 +- Doc/whatsnew/3.13.rst | 3 + Lib/test/test_sqlite3/test_backup.py | 2 - Lib/test/test_sqlite3/test_dbapi.py | 75 +++++++------------ Lib/test/test_sqlite3/test_hooks.py | 4 +- Lib/test/test_sqlite3/test_types.py | 1 - Lib/test/test_sqlite3/test_userfunctions.py | 34 +++------ ...-06-16-23-40-49.gh-issue-105875.naj8v5.rst | 2 + Modules/_sqlite/blob.c | 8 -- Modules/_sqlite/connection.c | 59 --------------- Modules/_sqlite/module.c | 44 +---------- configure | 20 ++--- configure.ac | 6 +- 13 files changed, 61 insertions(+), 202 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-06-16-23-40-49.gh-issue-105875.naj8v5.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index e7129fb3e4de6d..7544b88216e73c 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -29,7 +29,7 @@ PostgreSQL or Oracle. The :mod:`!sqlite3` module was written by Gerhard Häring. It provides an SQL interface compliant with the DB-API 2.0 specification described by :pep:`249`, and -requires SQLite 3.7.15 or newer. +requires SQLite 3.15.2 or newer. This document includes four main sections: @@ -734,9 +734,6 @@ Connection objects `deterministic `_, which allows SQLite to perform additional optimizations. - :raises NotSupportedError: - If *deterministic* is used with SQLite versions older than 3.8.3. - .. versionadded:: 3.8 The *deterministic* parameter. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 7f61ade808cce5..735715f0152898 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -410,6 +410,9 @@ Build Changes :file:`!configure`. (Contributed by Christian Heimes in :gh:`89886`.) +* SQLite 3.15.2 or newer is required to build the :mod:`sqlite3` extension module. + (Contributed by Erlend Aasland in :gh:`105875`.) + C API Changes ============= diff --git a/Lib/test/test_sqlite3/test_backup.py b/Lib/test/test_sqlite3/test_backup.py index 384dd9229ab341..87ab29c54d65e2 100644 --- a/Lib/test/test_sqlite3/test_backup.py +++ b/Lib/test/test_sqlite3/test_backup.py @@ -50,8 +50,6 @@ def test_bad_target_in_transaction(self): bck.executemany('INSERT INTO bar (key) VALUES (?)', [(3,), (4,)]) with self.assertRaises(sqlite.OperationalError) as cm: self.cx.backup(bck) - if sqlite.sqlite_version_info < (3, 8, 8): - self.assertEqual(str(cm.exception), 'target is in transaction') def test_keyword_only_args(self): with self.assertRaises(TypeError): diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 328b0467e7fa3d..3f9bd0248a8b96 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -165,6 +165,7 @@ def test_module_constants(self): "SQLITE_INTERNAL", "SQLITE_INTERRUPT", "SQLITE_IOERR", + "SQLITE_LIMIT_WORKER_THREADS", "SQLITE_LOCKED", "SQLITE_MISMATCH", "SQLITE_MISUSE", @@ -172,6 +173,7 @@ def test_module_constants(self): "SQLITE_NOMEM", "SQLITE_NOTADB", "SQLITE_NOTFOUND", + "SQLITE_NOTICE", "SQLITE_OK", "SQLITE_PERM", "SQLITE_PRAGMA", @@ -179,6 +181,7 @@ def test_module_constants(self): "SQLITE_RANGE", "SQLITE_READ", "SQLITE_READONLY", + "SQLITE_RECURSIVE", "SQLITE_REINDEX", "SQLITE_ROW", "SQLITE_SAVEPOINT", @@ -187,6 +190,7 @@ def test_module_constants(self): "SQLITE_TOOBIG", "SQLITE_TRANSACTION", "SQLITE_UPDATE", + "SQLITE_WARNING", # Run-time limit categories "SQLITE_LIMIT_LENGTH", "SQLITE_LIMIT_SQL_LENGTH", @@ -200,32 +204,43 @@ def test_module_constants(self): "SQLITE_LIMIT_VARIABLE_NUMBER", "SQLITE_LIMIT_TRIGGER_DEPTH", ] - if sqlite.sqlite_version_info >= (3, 7, 17): - consts += ["SQLITE_NOTICE", "SQLITE_WARNING"] - if sqlite.sqlite_version_info >= (3, 8, 3): - consts.append("SQLITE_RECURSIVE") - if sqlite.sqlite_version_info >= (3, 8, 7): - consts.append("SQLITE_LIMIT_WORKER_THREADS") consts += ["PARSE_DECLTYPES", "PARSE_COLNAMES"] # Extended result codes consts += [ "SQLITE_ABORT_ROLLBACK", + "SQLITE_AUTH_USER", "SQLITE_BUSY_RECOVERY", + "SQLITE_BUSY_SNAPSHOT", + "SQLITE_CANTOPEN_CONVPATH", "SQLITE_CANTOPEN_FULLPATH", "SQLITE_CANTOPEN_ISDIR", "SQLITE_CANTOPEN_NOTEMPDIR", + "SQLITE_CONSTRAINT_CHECK", + "SQLITE_CONSTRAINT_COMMITHOOK", + "SQLITE_CONSTRAINT_FOREIGNKEY", + "SQLITE_CONSTRAINT_FUNCTION", + "SQLITE_CONSTRAINT_NOTNULL", + "SQLITE_CONSTRAINT_PRIMARYKEY", + "SQLITE_CONSTRAINT_ROWID", + "SQLITE_CONSTRAINT_TRIGGER", + "SQLITE_CONSTRAINT_UNIQUE", + "SQLITE_CONSTRAINT_VTAB", "SQLITE_CORRUPT_VTAB", "SQLITE_IOERR_ACCESS", + "SQLITE_IOERR_AUTH", "SQLITE_IOERR_BLOCKED", "SQLITE_IOERR_CHECKRESERVEDLOCK", "SQLITE_IOERR_CLOSE", + "SQLITE_IOERR_CONVPATH", "SQLITE_IOERR_DELETE", "SQLITE_IOERR_DELETE_NOENT", "SQLITE_IOERR_DIR_CLOSE", "SQLITE_IOERR_DIR_FSYNC", "SQLITE_IOERR_FSTAT", "SQLITE_IOERR_FSYNC", + "SQLITE_IOERR_GETTEMPPATH", "SQLITE_IOERR_LOCK", + "SQLITE_IOERR_MMAP", "SQLITE_IOERR_NOMEM", "SQLITE_IOERR_RDLOCK", "SQLITE_IOERR_READ", @@ -237,50 +252,18 @@ def test_module_constants(self): "SQLITE_IOERR_SHORT_READ", "SQLITE_IOERR_TRUNCATE", "SQLITE_IOERR_UNLOCK", + "SQLITE_IOERR_VNODE", "SQLITE_IOERR_WRITE", "SQLITE_LOCKED_SHAREDCACHE", + "SQLITE_NOTICE_RECOVER_ROLLBACK", + "SQLITE_NOTICE_RECOVER_WAL", + "SQLITE_OK_LOAD_PERMANENTLY", "SQLITE_READONLY_CANTLOCK", + "SQLITE_READONLY_DBMOVED", "SQLITE_READONLY_RECOVERY", + "SQLITE_READONLY_ROLLBACK", + "SQLITE_WARNING_AUTOINDEX", ] - if sqlite.sqlite_version_info >= (3, 7, 16): - consts += [ - "SQLITE_CONSTRAINT_CHECK", - "SQLITE_CONSTRAINT_COMMITHOOK", - "SQLITE_CONSTRAINT_FOREIGNKEY", - "SQLITE_CONSTRAINT_FUNCTION", - "SQLITE_CONSTRAINT_NOTNULL", - "SQLITE_CONSTRAINT_PRIMARYKEY", - "SQLITE_CONSTRAINT_TRIGGER", - "SQLITE_CONSTRAINT_UNIQUE", - "SQLITE_CONSTRAINT_VTAB", - "SQLITE_READONLY_ROLLBACK", - ] - if sqlite.sqlite_version_info >= (3, 7, 17): - consts += [ - "SQLITE_IOERR_MMAP", - "SQLITE_NOTICE_RECOVER_ROLLBACK", - "SQLITE_NOTICE_RECOVER_WAL", - ] - if sqlite.sqlite_version_info >= (3, 8, 0): - consts += [ - "SQLITE_BUSY_SNAPSHOT", - "SQLITE_IOERR_GETTEMPPATH", - "SQLITE_WARNING_AUTOINDEX", - ] - if sqlite.sqlite_version_info >= (3, 8, 1): - consts += ["SQLITE_CANTOPEN_CONVPATH", "SQLITE_IOERR_CONVPATH"] - if sqlite.sqlite_version_info >= (3, 8, 2): - consts.append("SQLITE_CONSTRAINT_ROWID") - if sqlite.sqlite_version_info >= (3, 8, 3): - consts.append("SQLITE_READONLY_DBMOVED") - if sqlite.sqlite_version_info >= (3, 8, 7): - consts.append("SQLITE_AUTH_USER") - if sqlite.sqlite_version_info >= (3, 9, 0): - consts.append("SQLITE_IOERR_VNODE") - if sqlite.sqlite_version_info >= (3, 10, 0): - consts.append("SQLITE_IOERR_AUTH") - if sqlite.sqlite_version_info >= (3, 14, 1): - consts.append("SQLITE_OK_LOAD_PERMANENTLY") if sqlite.sqlite_version_info >= (3, 21, 0): consts += [ "SQLITE_IOERR_BEGIN_ATOMIC", @@ -330,8 +313,6 @@ def test_error_code_on_exception(self): self.assertEqual(e.sqlite_errorcode, err_code) self.assertTrue(e.sqlite_errorname.startswith("SQLITE_CANTOPEN")) - @unittest.skipIf(sqlite.sqlite_version_info <= (3, 7, 16), - "Requires SQLite 3.7.16 or newer") def test_extended_error_code_on_exception(self): with memory_database() as con: with con: diff --git a/Lib/test/test_sqlite3/test_hooks.py b/Lib/test/test_sqlite3/test_hooks.py index 21042b9bf106f7..89230c08cc9143 100644 --- a/Lib/test/test_sqlite3/test_hooks.py +++ b/Lib/test/test_sqlite3/test_hooks.py @@ -323,7 +323,7 @@ def test_trace_expanded_sql(self): ) def test_trace_too_much_expanded_sql(self): # If the expanded string is too large, we'll fall back to the - # unexpanded SQL statement (for SQLite 3.14.0 and newer). + # unexpanded SQL statement. # The resulting string length is limited by the runtime limit # SQLITE_LIMIT_LENGTH. template = "select 1 as a where a=" @@ -334,8 +334,6 @@ def test_trace_too_much_expanded_sql(self): unexpanded_query = template + "?" expected = [unexpanded_query] - if sqlite.sqlite_version_info < (3, 14, 0): - expected = [] with self.check_stmt_trace(cx, expected): cx.execute(unexpanded_query, (bad_param,)) diff --git a/Lib/test/test_sqlite3/test_types.py b/Lib/test/test_sqlite3/test_types.py index fde5f888e64009..66d27d21b8dc10 100644 --- a/Lib/test/test_sqlite3/test_types.py +++ b/Lib/test/test_sqlite3/test_types.py @@ -371,7 +371,6 @@ def test_cursor_description_insert(self): self.assertIsNone(self.cur.description) -@unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "CTEs not supported") class CommonTableExpressionTests(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py index 03d27531666c89..05c2fb3aa6f8f2 100644 --- a/Lib/test/test_sqlite3/test_userfunctions.py +++ b/Lib/test/test_sqlite3/test_userfunctions.py @@ -381,38 +381,22 @@ def append_result(arg): # Regarding deterministic functions: # # Between 3.8.3 and 3.15.0, deterministic functions were only used to - # optimize inner loops, so for those versions we can only test if the - # sqlite machinery has factored out a call or not. From 3.15.0 and onward, - # deterministic functions were permitted in WHERE clauses of partial - # indices, which allows testing based on syntax, iso. the query optimizer. - @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher") + # optimize inner loops. From 3.15.0 and onward, deterministic functions + # were permitted in WHERE clauses of partial indices, which allows testing + # based on syntax, iso. the query optimizer. def test_func_non_deterministic(self): mock = Mock(return_value=None) self.con.create_function("nondeterministic", 0, mock, deterministic=False) - if sqlite.sqlite_version_info < (3, 15, 0): - self.con.execute("select nondeterministic() = nondeterministic()") - self.assertEqual(mock.call_count, 2) - else: - with self.assertRaises(sqlite.OperationalError): - self.con.execute("create index t on test(t) where nondeterministic() is not null") + with self.assertRaises(sqlite.OperationalError): + self.con.execute("create index t on test(t) where nondeterministic() is not null") - @unittest.skipIf(sqlite.sqlite_version_info < (3, 8, 3), "Requires SQLite 3.8.3 or higher") def test_func_deterministic(self): mock = Mock(return_value=None) self.con.create_function("deterministic", 0, mock, deterministic=True) - if sqlite.sqlite_version_info < (3, 15, 0): - self.con.execute("select deterministic() = deterministic()") - self.assertEqual(mock.call_count, 1) - else: - try: - self.con.execute("create index t on test(t) where deterministic() is not null") - except sqlite.OperationalError: - self.fail("Unexpected failure while creating partial index") - - @unittest.skipIf(sqlite.sqlite_version_info >= (3, 8, 3), "SQLite < 3.8.3 needed") - def test_func_deterministic_not_supported(self): - with self.assertRaises(sqlite.NotSupportedError): - self.con.create_function("deterministic", 0, int, deterministic=True) + try: + self.con.execute("create index t on test(t) where deterministic() is not null") + except sqlite.OperationalError: + self.fail("Unexpected failure while creating partial index") def test_func_deterministic_keyword_only(self): with self.assertRaises(TypeError): diff --git a/Misc/NEWS.d/next/Build/2023-06-16-23-40-49.gh-issue-105875.naj8v5.rst b/Misc/NEWS.d/next/Build/2023-06-16-23-40-49.gh-issue-105875.naj8v5.rst new file mode 100644 index 00000000000000..5f60e65a2f6ae8 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-06-16-23-40-49.gh-issue-105875.naj8v5.rst @@ -0,0 +1,2 @@ +SQLite 3.15.2 or newer is required to build the :mod:`sqlite3` extension +module. Patch by Erlend Aasland. diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c index 76d261baf00f38..3096fb0c2135e4 100644 --- a/Modules/_sqlite/blob.c +++ b/Modules/_sqlite/blob.c @@ -108,14 +108,6 @@ static void blob_seterror(pysqlite_Blob *self, int rc) { assert(self->connection != NULL); -#if SQLITE_VERSION_NUMBER < 3008008 - // SQLite pre 3.8.8 does not set this blob error on the connection - if (rc == SQLITE_ABORT) { - PyErr_SetString(self->connection->OperationalError, - "Cannot operate on an expired blob handle"); - return; - } -#endif _pysqlite_seterror(self->connection->state, self->connection->db); } diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 82d23c2c30b798..d12d65500c654f 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -32,10 +32,6 @@ #include -#if SQLITE_VERSION_NUMBER >= 3014000 -#define HAVE_TRACE_V2 -#endif - #if SQLITE_VERSION_NUMBER >= 3025000 #define HAVE_WINDOW_FUNCTIONS #endif @@ -401,11 +397,7 @@ free_callback_contexts(pysqlite_Connection *self) static void remove_callbacks(sqlite3 *db) { -#ifdef HAVE_TRACE_V2 sqlite3_trace_v2(db, SQLITE_TRACE_STMT, 0, 0); -#else - sqlite3_trace(db, 0, (void*)0); -#endif sqlite3_progress_handler(db, 0, 0, (void *)0); (void)sqlite3_set_authorizer(db, NULL, NULL); } @@ -1086,18 +1078,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self, } if (deterministic) { -#if SQLITE_VERSION_NUMBER < 3008003 - PyErr_SetString(self->NotSupportedError, - "deterministic=True requires SQLite 3.8.3 or higher"); - return NULL; -#else - if (sqlite3_libversion_number() < 3008003) { - PyErr_SetString(self->NotSupportedError, - "deterministic=True requires SQLite 3.8.3 or higher"); - return NULL; - } flags |= SQLITE_DETERMINISTIC; -#endif } callback_context *ctx = create_callback_context(cls, func); if (ctx == NULL) { @@ -1376,7 +1357,6 @@ progress_callback(void *ctx) return rc; } -#ifdef HAVE_TRACE_V2 /* * From https://sqlite.org/c3ref/trace_v2.html: * The integer return value from the callback is currently ignored, though this @@ -1385,16 +1365,10 @@ progress_callback(void *ctx) */ static int trace_callback(unsigned int type, void *ctx, void *stmt, void *sql) -#else -static void -trace_callback(void *ctx, const char *sql) -#endif { -#ifdef HAVE_TRACE_V2 if (type != SQLITE_TRACE_STMT) { return 0; } -#endif PyGILState_STATE gilstate = PyGILState_Ensure(); @@ -1403,7 +1377,6 @@ trace_callback(void *ctx, const char *sql) assert(state != NULL); PyObject *py_statement = NULL; -#ifdef HAVE_TRACE_V2 const char *expanded_sql = sqlite3_expanded_sql((sqlite3_stmt *)stmt); if (expanded_sql == NULL) { sqlite3 *db = sqlite3_db_handle((sqlite3_stmt *)stmt); @@ -1423,15 +1396,6 @@ trace_callback(void *ctx, const char *sql) py_statement = PyUnicode_FromString(expanded_sql); sqlite3_free((void *)expanded_sql); } -#else - if (sql == NULL) { - PyErr_SetString(state->DataError, - "Expanded SQL string exceeds the maximum string length"); - print_or_clear_traceback((callback_context *)ctx); - goto exit; - } - py_statement = PyUnicode_FromString(sql); -#endif if (py_statement) { PyObject *callable = ((callback_context *)ctx)->callable; PyObject *ret = PyObject_CallOneArg(callable, py_statement); @@ -1444,9 +1408,7 @@ trace_callback(void *ctx, const char *sql) exit: PyGILState_Release(gilstate); -#ifdef HAVE_TRACE_V2 return 0; -#endif } /*[clinic input] @@ -1556,11 +1518,7 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, * - https://sqlite.org/c3ref/c_trace.html * - https://sqlite.org/c3ref/trace_v2.html */ -#ifdef HAVE_TRACE_V2 sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, 0, 0); -#else - sqlite3_trace(self->db, 0, (void*)0); -#endif set_callback_context(&self->trace_ctx, NULL); } else { @@ -1568,11 +1526,7 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, if (ctx == NULL) { return NULL; } -#ifdef HAVE_TRACE_V2 sqlite3_trace_v2(self->db, SQLITE_TRACE_STMT, trace_callback, ctx); -#else - sqlite3_trace(self->db, trace_callback, ctx); -#endif set_callback_context(&self->trace_ctx, ctx); } @@ -2000,15 +1954,6 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self, return NULL; } -#if SQLITE_VERSION_NUMBER < 3008008 - /* Since 3.8.8 this is already done, per commit - https://www.sqlite.org/src/info/169b5505498c0a7e */ - if (!sqlite3_get_autocommit(target->db)) { - PyErr_SetString(self->OperationalError, "target is in transaction"); - return NULL; - } -#endif - if (progress != Py_None && !PyCallable_Check(progress)) { PyErr_SetString(PyExc_TypeError, "progress argument must be a callable"); return NULL; @@ -2371,12 +2316,8 @@ is_int_config(const int op) switch (op) { case SQLITE_DBCONFIG_ENABLE_FKEY: case SQLITE_DBCONFIG_ENABLE_TRIGGER: -#if SQLITE_VERSION_NUMBER >= 3012002 case SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER: -#endif -#if SQLITE_VERSION_NUMBER >= 3013000 case SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION: -#endif #if SQLITE_VERSION_NUMBER >= 3016000 case SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE: #endif diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 27bd42f4595e1c..ea4d8c58b7ee0e 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -29,8 +29,8 @@ #include "row.h" #include "blob.h" -#if SQLITE_VERSION_NUMBER < 3007015 -#error "SQLite 3.7.15 or higher required" +#if SQLITE_VERSION_NUMBER < 3015002 +#error "SQLite 3.15.2 or higher required" #endif #define clinic_state() (pysqlite_get_state(module)) @@ -245,12 +245,6 @@ static PyMethodDef module_methods[] = { /* SQLite C API result codes. See also: * - https://www.sqlite.org/c3ref/c_abort_rollback.html - * - https://sqlite.org/changes.html#version_3_3_8 - * - https://sqlite.org/changes.html#version_3_7_16 - * - https://sqlite.org/changes.html#version_3_7_17 - * - https://sqlite.org/changes.html#version_3_8_0 - * - https://sqlite.org/changes.html#version_3_8_3 - * - https://sqlite.org/changes.html#version_3_14 * * Note: the SQLite changelogs rarely mention new result codes, so in order to * keep the 'error_codes' table in sync with SQLite, we must manually inspect @@ -294,10 +288,8 @@ static const struct { DECLARE_ERROR_CODE(SQLITE_ROW), DECLARE_ERROR_CODE(SQLITE_SCHEMA), DECLARE_ERROR_CODE(SQLITE_TOOBIG), -#if SQLITE_VERSION_NUMBER >= 3007017 DECLARE_ERROR_CODE(SQLITE_NOTICE), DECLARE_ERROR_CODE(SQLITE_WARNING), -#endif // Extended result code list DECLARE_ERROR_CODE(SQLITE_ABORT_ROLLBACK), DECLARE_ERROR_CODE(SQLITE_BUSY_RECOVERY), @@ -331,7 +323,6 @@ static const struct { DECLARE_ERROR_CODE(SQLITE_LOCKED_SHAREDCACHE), DECLARE_ERROR_CODE(SQLITE_READONLY_CANTLOCK), DECLARE_ERROR_CODE(SQLITE_READONLY_RECOVERY), -#if SQLITE_VERSION_NUMBER >= 3007016 DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_CHECK), DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_COMMITHOOK), DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_FOREIGNKEY), @@ -342,39 +333,20 @@ static const struct { DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_UNIQUE), DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_VTAB), DECLARE_ERROR_CODE(SQLITE_READONLY_ROLLBACK), -#endif -#if SQLITE_VERSION_NUMBER >= 3007017 DECLARE_ERROR_CODE(SQLITE_IOERR_MMAP), DECLARE_ERROR_CODE(SQLITE_NOTICE_RECOVER_ROLLBACK), DECLARE_ERROR_CODE(SQLITE_NOTICE_RECOVER_WAL), -#endif -#if SQLITE_VERSION_NUMBER >= 3008000 DECLARE_ERROR_CODE(SQLITE_BUSY_SNAPSHOT), DECLARE_ERROR_CODE(SQLITE_IOERR_GETTEMPPATH), DECLARE_ERROR_CODE(SQLITE_WARNING_AUTOINDEX), -#endif -#if SQLITE_VERSION_NUMBER >= 3008001 DECLARE_ERROR_CODE(SQLITE_CANTOPEN_CONVPATH), DECLARE_ERROR_CODE(SQLITE_IOERR_CONVPATH), -#endif -#if SQLITE_VERSION_NUMBER >= 3008002 DECLARE_ERROR_CODE(SQLITE_CONSTRAINT_ROWID), -#endif -#if SQLITE_VERSION_NUMBER >= 3008003 DECLARE_ERROR_CODE(SQLITE_READONLY_DBMOVED), -#endif -#if SQLITE_VERSION_NUMBER >= 3008007 DECLARE_ERROR_CODE(SQLITE_AUTH_USER), -#endif -#if SQLITE_VERSION_NUMBER >= 3009000 DECLARE_ERROR_CODE(SQLITE_IOERR_VNODE), -#endif -#if SQLITE_VERSION_NUMBER >= 3010000 DECLARE_ERROR_CODE(SQLITE_IOERR_AUTH), -#endif -#if SQLITE_VERSION_NUMBER >= 3014001 DECLARE_ERROR_CODE(SQLITE_OK_LOAD_PERMANENTLY), -#endif #if SQLITE_VERSION_NUMBER >= 3021000 DECLARE_ERROR_CODE(SQLITE_IOERR_BEGIN_ATOMIC), DECLARE_ERROR_CODE(SQLITE_IOERR_COMMIT_ATOMIC), @@ -481,9 +453,7 @@ add_integer_constants(PyObject *module) { ADD_INT(SQLITE_DROP_VTABLE); ADD_INT(SQLITE_FUNCTION); ADD_INT(SQLITE_SAVEPOINT); -#if SQLITE_VERSION_NUMBER >= 3008003 ADD_INT(SQLITE_RECURSIVE); -#endif // Run-time limit categories ADD_INT(SQLITE_LIMIT_LENGTH); ADD_INT(SQLITE_LIMIT_SQL_LENGTH); @@ -496,9 +466,7 @@ add_integer_constants(PyObject *module) { ADD_INT(SQLITE_LIMIT_LIKE_PATTERN_LENGTH); ADD_INT(SQLITE_LIMIT_VARIABLE_NUMBER); ADD_INT(SQLITE_LIMIT_TRIGGER_DEPTH); -#if SQLITE_VERSION_NUMBER >= 3008007 ADD_INT(SQLITE_LIMIT_WORKER_THREADS); -#endif /* * Database connection configuration options. @@ -506,12 +474,8 @@ add_integer_constants(PyObject *module) { */ ADD_INT(SQLITE_DBCONFIG_ENABLE_FKEY); ADD_INT(SQLITE_DBCONFIG_ENABLE_TRIGGER); -#if SQLITE_VERSION_NUMBER >= 3012002 ADD_INT(SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER); -#endif -#if SQLITE_VERSION_NUMBER >= 3013000 ADD_INT(SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION); -#endif #if SQLITE_VERSION_NUMBER >= 3016000 ADD_INT(SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE); #endif @@ -678,8 +642,8 @@ do { \ static int module_exec(PyObject *module) { - if (sqlite3_libversion_number() < 3007015) { - PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.7.15 or higher required"); + if (sqlite3_libversion_number() < 3015002) { + PyErr_SetString(PyExc_ImportError, MODULE_NAME ": SQLite 3.15.2 or higher required"); return -1; } diff --git a/configure b/configure index 7f17fe42120a2c..fdc7c22531785a 100755 --- a/configure +++ b/configure @@ -14552,12 +14552,12 @@ if test -n "$LIBSQLITE3_CFLAGS"; then pkg_cv_LIBSQLITE3_CFLAGS="$LIBSQLITE3_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 - ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.7.15") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.15.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.15.2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_LIBSQLITE3_CFLAGS=`$PKG_CONFIG --cflags "sqlite3 >= 3.7.15" 2>/dev/null` + pkg_cv_LIBSQLITE3_CFLAGS=`$PKG_CONFIG --cflags "sqlite3 >= 3.15.2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -14569,12 +14569,12 @@ if test -n "$LIBSQLITE3_LIBS"; then pkg_cv_LIBSQLITE3_LIBS="$LIBSQLITE3_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.7.15\""; } >&5 - ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.7.15") 2>&5 + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3 >= 3.15.2\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sqlite3 >= 3.15.2") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_LIBSQLITE3_LIBS=`$PKG_CONFIG --libs "sqlite3 >= 3.7.15" 2>/dev/null` + pkg_cv_LIBSQLITE3_LIBS=`$PKG_CONFIG --libs "sqlite3 >= 3.15.2" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -14595,9 +14595,9 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - LIBSQLITE3_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sqlite3 >= 3.7.15" 2>&1` + LIBSQLITE3_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sqlite3 >= 3.15.2" 2>&1` else - LIBSQLITE3_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sqlite3 >= 3.7.15" 2>&1` + LIBSQLITE3_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sqlite3 >= 3.15.2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$LIBSQLITE3_PKG_ERRORS" >&5 @@ -14646,8 +14646,8 @@ then : #include - #if SQLITE_VERSION_NUMBER < 3007015 - # error "SQLite 3.7.15 or higher required" + #if SQLITE_VERSION_NUMBER < 3015002 + # error "SQLite 3.15.2 or higher required" #endif int diff --git a/configure.ac b/configure.ac index ce4e4d4b061f0a..a24cd689730d7a 100644 --- a/configure.ac +++ b/configure.ac @@ -3952,7 +3952,7 @@ PY_CHECK_EMSCRIPTEN_PORT([LIBSQLITE3], [-sUSE_SQLITE3]) dnl Check for SQLite library. Use pkg-config if available. PKG_CHECK_MODULES( - [LIBSQLITE3], [sqlite3 >= 3.7.15], [], [ + [LIBSQLITE3], [sqlite3 >= 3.15.2], [], [ LIBSQLITE3_CFLAGS=${LIBSQLITE3_CFLAGS-""} LIBSQLITE3_LIBS=${LIBSQLITE3_LIBS-"-lsqlite3"} ] @@ -3978,8 +3978,8 @@ dnl hence CPPFLAGS instead of CFLAGS. AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([ #include - #if SQLITE_VERSION_NUMBER < 3007015 - # error "SQLite 3.7.15 or higher required" + #if SQLITE_VERSION_NUMBER < 3015002 + # error "SQLite 3.15.2 or higher required" #endif ], []) ], [ From 4426279a4399158027a1145cff1c4c92424bf5b5 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 19 Jun 2023 00:54:29 +0100 Subject: [PATCH 081/446] typing docs: Improve the intro to each section (#105901) --- Doc/library/typing.rst | 76 ++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 77cc6bc59ea2a1..dfd071fa136945 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -23,10 +23,9 @@ -------------- -This module provides runtime support for type hints. The most fundamental -support consists of the types :data:`Any`, :data:`Union`, :data:`Callable`, -:class:`TypeVar`, and :class:`Generic`. For a specification, please see -:pep:`484`. For a simplified introduction to type hints, see :pep:`483`. +This module provides runtime support for type hints. For the original +specification of the typing system, see :pep:`484`. For a simplified +introduction to type hints, see :pep:`483`. The function below takes and returns a string and is annotated as follows:: @@ -47,16 +46,18 @@ For a summary of deprecated features and a deprecation timeline, please see .. seealso:: - For a quick overview of type hints, refer to - `this cheat sheet `_. + `"Typing cheat sheet" `_ + A quick overview of type hints (hosted at the mypy docs) - The "Type System Reference" section of https://mypy.readthedocs.io/ -- since - the Python typing system is standardised via PEPs, this reference should - broadly apply to most Python type checkers, although some parts may still be - specific to mypy. + "Type System Reference" section of `the mypy docs `_ + The Python typing system is standardised via PEPs, so this reference + should broadly apply to most Python type checkers. (Some parts may still + be specific to mypy.) - The documentation at https://typing.readthedocs.io/ serves as useful reference - for type system features, useful typing related tools and typing best practices. + `"Static Typing with Python" `_ + Type-checker-agnostic documentation written by the community detailing + type system features, useful typing related tools and typing best + practices. .. _relevant-peps: @@ -654,25 +655,7 @@ can define new custom protocols to fully enjoy structural subtyping Module contents =============== -The module defines the following classes, functions and decorators. - -.. note:: - - This module defines several deprecated aliases to pre-existing - standard library classes. These were originally included in the typing - module in order to support parameterizing these generic classes using ``[]``. - However, the aliases became redundant in Python 3.9 when the - corresponding pre-existing classes were enhanced to support ``[]``. - - The redundant types are deprecated as of Python 3.9 but no - deprecation warnings are issued by the interpreter. - It is expected that type checkers will flag the deprecated types - when the checked program targets Python 3.9 or newer. - - The deprecated types will be removed from the :mod:`typing` module - no sooner than the first Python version released 5 years after the release of Python 3.9.0. - See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. - +The ``typing`` module defines the following classes, functions and decorators. Special typing primitives ------------------------- @@ -680,7 +663,8 @@ Special typing primitives Special types """"""""""""" -These can be used as types in annotations and do not support ``[]``. +These can be used as types in annotations. They do not support subscription +using ``[]``. .. data:: Any @@ -890,7 +874,8 @@ These can be used as types in annotations and do not support ``[]``. Special forms """"""""""""" -These can be used as types in annotations using ``[]``, each having a unique syntax. +These can be used as types in annotations. They all support subscription using +``[]``, but each has a unique syntax. .. data:: Tuple @@ -1471,7 +1456,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn Building generic types and type aliases """"""""""""""""""""""""""""""""""""""" -The following objects are not used directly in annotations. Instead, they are building blocks +The following classes should not be used directly as annotations. +Their intended purpose is to be building blocks for creating generic types and type aliases. These objects can be created through special syntax @@ -1962,7 +1948,9 @@ without the dedicated syntax, as documented below. Other special directives """""""""""""""""""""""" -These are not used in annotations. They are building blocks for declaring types. +These functions and classes should not be used directly as annotations. +Their intended purpose is to be building blocks for creating and declaring +types. .. class:: NamedTuple @@ -2399,7 +2387,8 @@ These are not used in annotations. They are building blocks for declaring types. Protocols --------- -These protocols are decorated with :func:`runtime_checkable`. +The following protocols are provided by the typing module. All are decorated +with :func:`@runtime_checkable `. .. class:: SupportsAbs @@ -3069,6 +3058,21 @@ Constant Deprecated aliases ------------------ +This module defines several deprecated aliases to pre-existing +standard library classes. These were originally included in the typing +module in order to support parameterizing these generic classes using ``[]``. +However, the aliases became redundant in Python 3.9 when the +corresponding pre-existing classes were enhanced to support ``[]``. + +The redundant types are deprecated as of Python 3.9 but no +deprecation warnings are issued by the interpreter. +It is expected that type checkers will flag the deprecated types +when the checked program targets Python 3.9 or newer. + +The deprecated types will be removed from the :mod:`typing` module +no sooner than the first Python version released 5 years after the release of Python 3.9.0. +See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. + .. _corresponding-to-built-in-types: Aliases to built-in types From 581619941ecce986a2fc8cbddd95256daa25fb26 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 19 Jun 2023 10:32:20 +0100 Subject: [PATCH 082/446] GH-104584: Assorted fixes for the optimizer API. (GH-105683) * Add test for long loops * Clear ENTER_EXECUTOR when deopting code objects. --- Lib/test/test_capi/test_misc.py | 65 ++++++- Modules/_testinternalcapi.c | 10 + Objects/codeobject.c | 24 ++- Python/bytecodes.c | 3 +- Python/generated_cases.c.h | 325 ++++++++++++++++---------------- Python/optimizer.c | 73 ++++--- 6 files changed, 297 insertions(+), 203 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index ccec27d3e0b64c..f2aa2a07783eec 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2347,17 +2347,66 @@ def func(): class TestOptimizerAPI(unittest.TestCase): - def test_counter_optimizer(self): - opt = _testinternalcapi.get_counter_optimizer() - self.assertEqual(opt.get_count(), 0) + @contextlib.contextmanager + def temporary_optimizer(self, opt): + _testinternalcapi.set_optimizer(opt) try: - _testinternalcapi.set_optimizer(opt) - self.assertEqual(opt.get_count(), 0) - for _ in range(1000): - pass - self.assertEqual(opt.get_count(), 1000) + yield finally: _testinternalcapi.set_optimizer(None) + @contextlib.contextmanager + def clear_executors(self, func): + try: + yield + finally: + #Clear executors + func.__code__ = func.__code__.replace() + + def test_get_set_optimizer(self): + self.assertEqual(_testinternalcapi.get_optimizer(), None) + opt = _testinternalcapi.get_counter_optimizer() + _testinternalcapi.set_optimizer(opt) + self.assertEqual(_testinternalcapi.get_optimizer(), opt) + _testinternalcapi.set_optimizer(None) + self.assertEqual(_testinternalcapi.get_optimizer(), None) + + def test_counter_optimizer(self): + + def loop(): + for _ in range(1000): + pass + + for repeat in range(5): + opt = _testinternalcapi.get_counter_optimizer() + with self.temporary_optimizer(opt): + self.assertEqual(opt.get_count(), 0) + with self.clear_executors(loop): + loop() + self.assertEqual(opt.get_count(), 1000) + + def test_long_loop(self): + "Check that we aren't confused by EXTENDED_ARG" + + def nop(): + pass + + def long_loop(): + for _ in range(10): + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + + opt = _testinternalcapi.get_counter_optimizer() + with self.temporary_optimizer(opt): + self.assertEqual(opt.get_count(), 0) + long_loop() + self.assertEqual(opt.get_count(), 10) + + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 3de32a32750ebc..0a3b0dd539e862 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -840,6 +840,15 @@ set_optimizer(PyObject *self, PyObject *opt) Py_RETURN_NONE; } +static PyObject * +get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *opt = (PyObject *)PyUnstable_GetOptimizer(); + if (opt == NULL) { + Py_RETURN_NONE; + } + return opt; +} static int _pending_callback(void *arg) { @@ -982,6 +991,7 @@ static PyMethodDef module_functions[] = { {"iframe_getcode", iframe_getcode, METH_O, NULL}, {"iframe_getline", iframe_getline, METH_O, NULL}, {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, + {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"get_counter_optimizer", get_counter_optimizer, METH_NOARGS, NULL}, {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 377cac55848fbd..a53584c4795e90 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1465,12 +1465,28 @@ PyCode_GetFreevars(PyCodeObject *code) return _PyCode_GetFreevars(code); } +static void +clear_executors(PyCodeObject *co) +{ + for (int i = 0; i < co->co_executors->size; i++) { + Py_CLEAR(co->co_executors->executors[i]); + } + PyMem_Free(co->co_executors); + co->co_executors = NULL; +} + static void deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions) { Py_ssize_t len = Py_SIZE(code); for (int i = 0; i < len; i++) { int opcode = _Py_GetBaseOpcode(code, i); + if (opcode == ENTER_EXECUTOR) { + _PyExecutorObject *exec = code->co_executors->executors[instructions[i].op.arg]; + opcode = exec->vm_data.opcode; + instructions[i].op.arg = exec->vm_data.oparg; + } + assert(opcode != ENTER_EXECUTOR); int caches = _PyOpcode_Caches[opcode]; instructions[i].op.code = opcode; for (int j = 1; j <= caches; j++) { @@ -1679,10 +1695,7 @@ code_dealloc(PyCodeObject *co) PyMem_Free(co_extra); } if (co->co_executors != NULL) { - for (int i = 0; i < co->co_executors->size; i++) { - Py_CLEAR(co->co_executors->executors[i]); - } - PyMem_Free(co->co_executors); + clear_executors(co); } Py_XDECREF(co->co_consts); @@ -2278,6 +2291,9 @@ void _PyStaticCode_Fini(PyCodeObject *co) { deopt_code(co, _PyCode_CODE(co)); + if (co->co_executors != NULL) { + clear_executors(co); + } PyMem_Free(co->co_extra); if (co->_co_cached != NULL) { Py_CLEAR(co->_co_cached->_co_code); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a2cb834df29822..a7acff65e13e3a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2157,6 +2157,7 @@ dummy_func( frame = cframe.current_frame; goto error; } + assert(frame == cframe.current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); goto resume_frame; } @@ -2176,7 +2177,7 @@ dummy_func( inst(ENTER_EXECUTOR, (--)) { PyCodeObject *code = _PyFrame_GetCode(frame); - _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg]; + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 13c3e286e2ddbf..717b29e811d309 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3077,19 +3077,20 @@ frame = cframe.current_frame; goto error; } + assert(frame == cframe.current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3085 "Python/generated_cases.c.h" + #line 3086 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2178 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); - _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg]; + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { @@ -3097,20 +3098,20 @@ goto error; } goto resume_frame; - #line 3101 "Python/generated_cases.c.h" + #line 3102 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2190 "Python/bytecodes.c" + #line 2191 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3112 "Python/generated_cases.c.h" + #line 3113 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2196 "Python/bytecodes.c" + #line 2197 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3118,22 +3119,22 @@ if (err < 0) goto pop_1_error; } } - #line 3122 "Python/generated_cases.c.h" + #line 3123 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2206 "Python/bytecodes.c" + #line 2207 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3135 "Python/generated_cases.c.h" + #line 3136 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2212 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3141,63 +3142,63 @@ if (err < 0) goto pop_1_error; } } - #line 3145 "Python/generated_cases.c.h" + #line 3146 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2222 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3154 "Python/generated_cases.c.h" + #line 3155 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2224 "Python/bytecodes.c" + #line 2225 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3159 "Python/generated_cases.c.h" + #line 3160 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2229 "Python/bytecodes.c" + #line 2230 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3171 "Python/generated_cases.c.h" + #line 3172 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2234 "Python/bytecodes.c" + #line 2235 "Python/bytecodes.c" } - #line 3175 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2238 "Python/bytecodes.c" + #line 2239 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3188 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2247 "Python/bytecodes.c" + #line 2248 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3201 "Python/generated_cases.c.h" + #line 3202 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3208,16 +3209,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2255 "Python/bytecodes.c" + #line 2256 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3217 "Python/generated_cases.c.h" + #line 3218 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2260 "Python/bytecodes.c" + #line 2261 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3225,7 +3226,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3229 "Python/generated_cases.c.h" + #line 3230 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3234,10 +3235,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2270 "Python/bytecodes.c" + #line 2271 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3241 "Python/generated_cases.c.h" + #line 3242 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3246,10 +3247,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2275 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3253 "Python/generated_cases.c.h" + #line 3254 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3259,11 +3260,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2280 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3267 "Python/generated_cases.c.h" + #line 3268 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3272,14 +3273,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2286 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3279 "Python/generated_cases.c.h" + #line 3280 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2289 "Python/bytecodes.c" + #line 2290 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3283 "Python/generated_cases.c.h" + #line 3284 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3287,7 +3288,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2293 "Python/bytecodes.c" + #line 2294 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3310,11 +3311,11 @@ if (iter == NULL) { goto error; } - #line 3314 "Python/generated_cases.c.h" + #line 3315 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2316 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" } - #line 3318 "Python/generated_cases.c.h" + #line 3319 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3324,7 +3325,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2334 "Python/bytecodes.c" + #line 2335 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3356,7 +3357,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3360 "Python/generated_cases.c.h" + #line 3361 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3364,7 +3365,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2368 "Python/bytecodes.c" + #line 2369 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3390,14 +3391,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3394 "Python/generated_cases.c.h" + #line 3395 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2396 "Python/bytecodes.c" + #line 2397 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3418,7 +3419,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3422 "Python/generated_cases.c.h" + #line 3423 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3428,7 +3429,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2419 "Python/bytecodes.c" + #line 2420 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3449,7 +3450,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3453 "Python/generated_cases.c.h" + #line 3454 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3459,7 +3460,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2442 "Python/bytecodes.c" + #line 2443 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3478,7 +3479,7 @@ if (next == NULL) { goto error; } - #line 3482 "Python/generated_cases.c.h" + #line 3483 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3487,7 +3488,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2463 "Python/bytecodes.c" + #line 2464 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3503,14 +3504,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3507 "Python/generated_cases.c.h" + #line 3508 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2481 "Python/bytecodes.c" + #line 2482 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3533,16 +3534,16 @@ Py_DECREF(enter); goto error; } - #line 3537 "Python/generated_cases.c.h" + #line 3538 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2504 "Python/bytecodes.c" + #line 2505 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3546 "Python/generated_cases.c.h" + #line 3547 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3553,7 +3554,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2513 "Python/bytecodes.c" + #line 2514 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3579,16 +3580,16 @@ Py_DECREF(enter); goto error; } - #line 3583 "Python/generated_cases.c.h" + #line 3584 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2539 "Python/bytecodes.c" + #line 2540 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3592 "Python/generated_cases.c.h" + #line 3593 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3600,7 +3601,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2548 "Python/bytecodes.c" + #line 2549 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3621,7 +3622,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3625 "Python/generated_cases.c.h" + #line 3626 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3630,7 +3631,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2587 "Python/bytecodes.c" + #line 2588 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3640,7 +3641,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3644 "Python/generated_cases.c.h" + #line 3645 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3654,7 +3655,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2599 "Python/bytecodes.c" + #line 2600 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3671,7 +3672,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3675 "Python/generated_cases.c.h" + #line 3676 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3685,7 +3686,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2618 "Python/bytecodes.c" + #line 2619 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3695,7 +3696,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3699 "Python/generated_cases.c.h" + #line 3700 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3709,7 +3710,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2630 "Python/bytecodes.c" + #line 2631 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3723,7 +3724,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3727 "Python/generated_cases.c.h" + #line 3728 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3732,16 +3733,16 @@ } TARGET(KW_NAMES) { - #line 2646 "Python/bytecodes.c" + #line 2647 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3740 "Python/generated_cases.c.h" + #line 3741 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2652 "Python/bytecodes.c" + #line 2653 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3754,7 +3755,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3758 "Python/generated_cases.c.h" + #line 3759 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3764,7 +3765,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2697 "Python/bytecodes.c" + #line 2698 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3846,7 +3847,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3850 "Python/generated_cases.c.h" + #line 3851 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3858,7 +3859,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2785 "Python/bytecodes.c" + #line 2786 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3868,7 +3869,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3872 "Python/generated_cases.c.h" + #line 3873 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3877,7 +3878,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2797 "Python/bytecodes.c" + #line 2798 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3903,7 +3904,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3907 "Python/generated_cases.c.h" + #line 3908 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3911,7 +3912,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2825 "Python/bytecodes.c" + #line 2826 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3947,7 +3948,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3951 "Python/generated_cases.c.h" + #line 3952 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3955,7 +3956,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2863 "Python/bytecodes.c" + #line 2864 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3965,7 +3966,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3969 "Python/generated_cases.c.h" + #line 3970 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3978,7 +3979,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2875 "Python/bytecodes.c" + #line 2876 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3989,7 +3990,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3993 "Python/generated_cases.c.h" + #line 3994 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4003,7 +4004,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2889 "Python/bytecodes.c" + #line 2890 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4014,7 +4015,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4018 "Python/generated_cases.c.h" + #line 4019 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4028,7 +4029,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2903 "Python/bytecodes.c" + #line 2904 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4050,7 +4051,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4054 "Python/generated_cases.c.h" + #line 4055 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4064,7 +4065,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2928 "Python/bytecodes.c" + #line 2929 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4092,7 +4093,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4096 "Python/generated_cases.c.h" + #line 4097 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4106,7 +4107,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2959 "Python/bytecodes.c" + #line 2960 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4138,7 +4139,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4142 "Python/generated_cases.c.h" + #line 4143 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4152,7 +4153,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2994 "Python/bytecodes.c" + #line 2995 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4184,7 +4185,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4188 "Python/generated_cases.c.h" + #line 4189 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4198,7 +4199,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3029 "Python/bytecodes.c" + #line 3030 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4223,7 +4224,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4227 "Python/generated_cases.c.h" + #line 4228 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4236,7 +4237,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3056 "Python/bytecodes.c" + #line 3057 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4263,7 +4264,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4267 "Python/generated_cases.c.h" + #line 4268 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4275,7 +4276,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3086 "Python/bytecodes.c" + #line 3087 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4293,14 +4294,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4297 "Python/generated_cases.c.h" + #line 4298 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3106 "Python/bytecodes.c" + #line 3107 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4331,7 +4332,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4335 "Python/generated_cases.c.h" + #line 4336 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4344,7 +4345,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3140 "Python/bytecodes.c" + #line 3141 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4373,7 +4374,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4377 "Python/generated_cases.c.h" + #line 4378 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4386,7 +4387,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3172 "Python/bytecodes.c" + #line 3173 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4415,7 +4416,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4419 "Python/generated_cases.c.h" + #line 4420 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4428,7 +4429,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3204 "Python/bytecodes.c" + #line 3205 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4456,7 +4457,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4460 "Python/generated_cases.c.h" + #line 4461 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4466,9 +4467,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3235 "Python/bytecodes.c" + #line 3236 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4472 "Python/generated_cases.c.h" + #line 4473 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4477,7 +4478,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3239 "Python/bytecodes.c" + #line 3240 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4539,14 +4540,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4543 "Python/generated_cases.c.h" + #line 4544 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3301 "Python/bytecodes.c" + #line 3302 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4550 "Python/generated_cases.c.h" + #line 4551 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4557,7 +4558,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3307 "Python/bytecodes.c" + #line 3308 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4569,7 +4570,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4573 "Python/generated_cases.c.h" + #line 4574 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4577,7 +4578,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3321 "Python/bytecodes.c" + #line 3322 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4602,14 +4603,14 @@ default: Py_UNREACHABLE(); } - #line 4606 "Python/generated_cases.c.h" + #line 4607 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3348 "Python/bytecodes.c" + #line 3349 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4630,7 +4631,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4634 "Python/generated_cases.c.h" + #line 4635 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4638,15 +4639,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3371 "Python/bytecodes.c" + #line 3372 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4644 "Python/generated_cases.c.h" + #line 4645 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3373 "Python/bytecodes.c" + #line 3374 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4650 "Python/generated_cases.c.h" + #line 4651 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4656,14 +4657,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3377 "Python/bytecodes.c" + #line 3378 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4667 "Python/generated_cases.c.h" + #line 4668 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4671,7 +4672,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3386 "Python/bytecodes.c" + #line 3387 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4682,7 +4683,7 @@ else { res = value; } - #line 4686 "Python/generated_cases.c.h" + #line 4687 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4691,12 +4692,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3399 "Python/bytecodes.c" + #line 3400 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4700 "Python/generated_cases.c.h" + #line 4701 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4705,10 +4706,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3406 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4712 "Python/generated_cases.c.h" + #line 4713 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4720,7 +4721,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3411 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4735,12 +4736,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4739 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3426 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4744 "Python/generated_cases.c.h" + #line 4745 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4750,16 +4751,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3431 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" assert(oparg >= 2); - #line 4756 "Python/generated_cases.c.h" + #line 4757 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3435 "Python/bytecodes.c" + #line 3436 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4771,26 +4772,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4775 "Python/generated_cases.c.h" + #line 4776 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3449 "Python/bytecodes.c" + #line 3450 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4781 "Python/generated_cases.c.h" + #line 4782 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3453 "Python/bytecodes.c" + #line 3454 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4788 "Python/generated_cases.c.h" + #line 4789 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3458 "Python/bytecodes.c" + #line 3459 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4799,12 +4800,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4803 "Python/generated_cases.c.h" + #line 4804 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3469 "Python/bytecodes.c" + #line 3470 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4813,12 +4814,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4817 "Python/generated_cases.c.h" + #line 4818 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3480 "Python/bytecodes.c" + #line 3481 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4830,12 +4831,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4834 "Python/generated_cases.c.h" + #line 4835 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3494 "Python/bytecodes.c" + #line 3495 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4847,30 +4848,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4851 "Python/generated_cases.c.h" + #line 4852 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3508 "Python/bytecodes.c" + #line 3509 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4862 "Python/generated_cases.c.h" + #line 4863 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3516 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4869 "Python/generated_cases.c.h" + #line 4870 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3521 "Python/bytecodes.c" + #line 3522 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4876 "Python/generated_cases.c.h" + #line 4877 "Python/generated_cases.c.h" } diff --git a/Python/optimizer.c b/Python/optimizer.c index 8f7a9727218655..95cd7824e32e42 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -9,20 +9,31 @@ #include #include -/* Returns the index of the next space, or -1 if there is no - * more space. Doesn't set an exception. */ +static bool +has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) +{ + if (instr->op.code == ENTER_EXECUTOR) { + return true; + } + if (code->co_executors == NULL) { + return true; + } + return code->co_executors->size < 256; +} + static int32_t -get_next_free_in_executor_array(PyCodeObject *code) +get_index_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) { + if (instr->op.code == ENTER_EXECUTOR) { + return instr->op.arg; + } _PyExecutorArray *old = code->co_executors; int size = 0; int capacity = 0; if (old != NULL) { size = old->size; capacity = old->capacity; - if (capacity >= 256) { - return -1; - } + assert(size < 256); } assert(size <= capacity); if (size == capacity) { @@ -40,46 +51,36 @@ get_next_free_in_executor_array(PyCodeObject *code) code->co_executors = new; } assert(size < code->co_executors->capacity); - code->co_executors->size++; return size; } static void insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorObject *executor) { + Py_INCREF(executor); if (instr->op.code == ENTER_EXECUTOR) { assert(index == instr->op.arg); _PyExecutorObject *old = code->co_executors->executors[index]; executor->vm_data.opcode = old->vm_data.opcode; executor->vm_data.oparg = old->vm_data.oparg; old->vm_data.opcode = 0; - Py_INCREF(executor); code->co_executors->executors[index] = executor; Py_DECREF(old); } else { - Py_INCREF(executor); + assert(code->co_executors->size == index); + assert(code->co_executors->capacity > index); executor->vm_data.opcode = instr->op.code; executor->vm_data.oparg = instr->op.arg; code->co_executors->executors[index] = executor; assert(index < 256); instr->op.code = ENTER_EXECUTOR; instr->op.arg = index; + code->co_executors->size++; } return; } -static int -get_executor_index(PyCodeObject *code, _Py_CODEUNIT *instr) -{ - if (instr->op.code == ENTER_EXECUTOR) { - return instr->op.arg; - } - else { - return get_next_free_in_executor_array(code); - } -} - int PyUnstable_Replace_Executor(PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject *new) { @@ -87,7 +88,7 @@ PyUnstable_Replace_Executor(PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutor PyErr_Format(PyExc_ValueError, "No executor to replace"); return -1; } - int index = get_executor_index(code, instr); + int index = instr->op.arg; assert(index >= 0); insert_executor(code, instr, index, new); return 0; @@ -126,6 +127,8 @@ PyUnstable_GetOptimizer(void) if (interp->optimizer == &_PyOptimizer_Default) { return NULL; } + assert(interp->optimizer_backedge_threshold == interp->optimizer->backedge_threshold); + assert(interp->optimizer_resume_threshold == interp->optimizer->resume_threshold); Py_INCREF(interp->optimizer); return interp->optimizer; } @@ -151,23 +154,37 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI PyCodeObject *code = (PyCodeObject *)frame->f_executable; assert(PyCode_Check(code)); PyInterpreterState *interp = PyInterpreterState_Get(); - int index = get_executor_index(code, src); - if (index < 0) { - _PyFrame_SetStackPointer(frame, stack_pointer); - return frame; + if (!has_space_for_executor(code, src)) { + goto jump_to_destination; } _PyOptimizerObject *opt = interp->optimizer; - _PyExecutorObject *executor; + _PyExecutorObject *executor = NULL; int err = opt->optimize(opt, code, dest, &executor); if (err <= 0) { + assert(executor == NULL); if (err < 0) { return NULL; } - _PyFrame_SetStackPointer(frame, stack_pointer); - return frame; + goto jump_to_destination; + } + int index = get_index_for_executor(code, src); + if (index < 0) { + /* Out of memory. Don't raise and assume that the + * error will show up elsewhere. + * + * If an optimizer has already produced an executor, + * it might get confused by the executor disappearing, + * but there is not much we can do about that here. */ + Py_DECREF(executor); + goto jump_to_destination; } insert_executor(code, src, index, executor); + assert(frame->prev_instr == src); return executor->execute(executor, frame, stack_pointer); +jump_to_destination: + frame->prev_instr = dest - 1; + _PyFrame_SetStackPointer(frame, stack_pointer); + return frame; } /** Test support **/ From ab3823a97bdeefb0266b3c8d493f7f6223ce3686 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Mon, 19 Jun 2023 13:31:57 +0200 Subject: [PATCH 083/446] gh-71299: Fix __all__ in tokenize (#105907) Co-authored-by: Unit03 --- Lib/test/test_tokenize.py | 268 +++++++++++++++++++------------------- Lib/tokenize.py | 4 +- 2 files changed, 137 insertions(+), 135 deletions(-) diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 5ad278499c9df9..97c4884f6e33b8 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -1,20 +1,16 @@ -from test import support -from test.support import os_helper -from tokenize import (tokenize, untokenize, NUMBER, NAME, OP, - STRING, ENDMARKER, ENCODING, tok_name, detect_encoding, - open as tokenize_open, Untokenizer, generate_tokens, - NEWLINE, _generate_tokens_from_c_tokenizer, DEDENT, TokenInfo, - TokenError) -from io import BytesIO, StringIO +import os +import token +import tokenize import unittest +from io import BytesIO, StringIO from textwrap import dedent from unittest import TestCase, mock +from test import support +from test.support import os_helper from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) from test.support import os_helper from test.support.script_helper import run_test_script, make_script, run_python_until_end -import os -import token # Converts a source string into a list of textual representation # of the tokens such as: @@ -26,12 +22,12 @@ def stringify_tokens_from_source(token_generator, source_string): missing_trailing_nl = source_string[-1] not in '\r\n' for type, token, start, end, line in token_generator: - if type == ENDMARKER: + if type == tokenize.ENDMARKER: break # Ignore the new line on the last line if the input lacks one - if missing_trailing_nl and type == NEWLINE and end[0] == num_lines: + if missing_trailing_nl and type == tokenize.NEWLINE and end[0] == num_lines: continue - type = tok_name[type] + type = tokenize.tok_name[type] result.append(f" {type:10} {token!r:13} {start} {end}") return result @@ -47,7 +43,7 @@ def check_tokenize(self, s, expected): # Format the tokens in s in a table format. # The ENDMARKER and final NEWLINE are omitted. f = BytesIO(s.encode('utf-8')) - result = stringify_tokens_from_source(tokenize(f.readline), s) + result = stringify_tokens_from_source(tokenize.tokenize(f.readline), s) self.assertEqual(result, [" ENCODING 'utf-8' (0, 0) (0, 0)"] + expected.rstrip().splitlines()) @@ -57,27 +53,27 @@ def gen(): yield "sdfosdg" yield "sdfosdg" with self.assertRaises(TypeError): - list(tokenize(gen().__next__)) + list(tokenize.tokenize(gen().__next__)) def gen(): yield b"sdfosdg" yield b"sdfosdg" with self.assertRaises(TypeError): - list(generate_tokens(gen().__next__)) + list(tokenize.generate_tokens(gen().__next__)) def gen(): yield "sdfosdg" 1/0 with self.assertRaises(ZeroDivisionError): - list(generate_tokens(gen().__next__)) + list(tokenize.generate_tokens(gen().__next__)) def test_implicit_newline(self): # Make sure that the tokenizer puts in an implicit NEWLINE # when the input lacks a trailing new line. f = BytesIO("x".encode('utf-8')) - tokens = list(tokenize(f.readline)) - self.assertEqual(tokens[-2].type, NEWLINE) - self.assertEqual(tokens[-1].type, ENDMARKER) + tokens = list(tokenize.tokenize(f.readline)) + self.assertEqual(tokens[-2].type, tokenize.NEWLINE) + self.assertEqual(tokens[-1].type, tokenize.ENDMARKER) def test_basic(self): self.check_tokenize("1 + 1", """\ @@ -139,7 +135,7 @@ def k(x): with self.assertRaisesRegex(IndentationError, "unindent does not match any " "outer indentation level") as e: - for tok in tokenize(readline): + for tok in tokenize.tokenize(readline): pass self.assertEqual(e.exception.lineno, 3) self.assertEqual(e.exception.filename, '') @@ -275,8 +271,8 @@ def test_float(self): def test_underscore_literals(self): def number_token(s): f = BytesIO(s.encode('utf-8')) - for toktype, token, start, end, line in tokenize(f.readline): - if toktype == NUMBER: + for toktype, token, start, end, line in tokenize.tokenize(f.readline): + if toktype == tokenize.NUMBER: return token return 'invalid token' for lit in VALID_UNDERSCORE_LITERALS: @@ -292,7 +288,7 @@ def number_token(s): continue try: number_token(lit) - except TokenError: + except tokenize.TokenError: continue self.assertNotEqual(number_token(lit), lit) @@ -1150,24 +1146,24 @@ def check_tokenize(self, s, expected): # Format the tokens in s in a table format. # The ENDMARKER and final NEWLINE are omitted. f = StringIO(s) - result = stringify_tokens_from_source(generate_tokens(f.readline), s) + result = stringify_tokens_from_source(tokenize.generate_tokens(f.readline), s) self.assertEqual(result, expected.rstrip().splitlines()) def decistmt(s): result = [] - g = tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize the string + g = tokenize.tokenize(BytesIO(s.encode('utf-8')).readline) # tokenize the string for toknum, tokval, _, _, _ in g: - if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens + if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens result.extend([ - (NAME, 'Decimal'), - (OP, '('), - (STRING, repr(tokval)), - (OP, ')') + (tokenize.NAME, 'Decimal'), + (tokenize.OP, '('), + (tokenize.STRING, repr(tokval)), + (tokenize.OP, ')') ]) else: result.append((toknum, tokval)) - return untokenize(result).decode('utf-8').strip() + return tokenize.untokenize(result).decode('utf-8').strip() class TestMisc(TestCase): @@ -1191,6 +1187,13 @@ def test_decistmt(self): self.assertEqual(eval(decistmt(s)), Decimal('-3.217160342717258261933904529E-7')) + def test___all__(self): + expected = token.__all__ + [ + "TokenInfo", "TokenError", "generate_tokens", + "detect_encoding", "untokenize", "open", "tokenize", + ] + self.assertCountEqual(tokenize.__all__, expected) + class TestTokenizerAdheresToPep0263(TestCase): """ @@ -1245,9 +1248,10 @@ def readline(): yield b'' # skip the initial encoding token and the end tokens - tokens = list(_generate_tokens_from_c_tokenizer(readline().__next__, encoding='utf-8', - extra_tokens=True))[:-2] - expected_tokens = [TokenInfo(3, '"ЉЊЈЁЂ"', (1, 0), (1, 7), '"ЉЊЈЁЂ"')] + tokens = list(tokenize._generate_tokens_from_c_tokenizer(readline().__next__, + encoding='utf-8', + extra_tokens=True))[:-2] + expected_tokens = [tokenize.TokenInfo(3, '"ЉЊЈЁЂ"', (1, 0), (1, 7), '"ЉЊЈЁЂ"')] self.assertEqual(tokens, expected_tokens, "bytes not decoded with encoding") @@ -1271,7 +1275,7 @@ def test_no_bom_no_encoding_cookie(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8') self.assertEqual(consumed_lines, list(lines[:2])) @@ -1281,7 +1285,7 @@ def test_bom_no_cookie(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, [b'# something\n', b'print(something)\n']) @@ -1292,7 +1296,7 @@ def test_cookie_first_line_no_bom(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'iso-8859-1') self.assertEqual(consumed_lines, [b'# -*- coding: latin-1 -*-\n']) @@ -1302,7 +1306,7 @@ def test_matched_bom_and_cookie_first_line(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, [b'# coding=utf-8\n']) @@ -1313,7 +1317,7 @@ def test_mismatched_bom_and_cookie_first_line_raises_syntaxerror(self): b'do_something(else)\n' ) readline = self.get_readline(lines) - self.assertRaises(SyntaxError, detect_encoding, readline) + self.assertRaises(SyntaxError, tokenize.detect_encoding, readline) def test_cookie_second_line_no_bom(self): lines = ( @@ -1322,7 +1326,7 @@ def test_cookie_second_line_no_bom(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'ascii') expected = [b'#! something\n', b'# vim: set fileencoding=ascii :\n'] self.assertEqual(consumed_lines, expected) @@ -1334,7 +1338,7 @@ def test_matched_bom_and_cookie_second_line(self): b'print(something)\n', b'do_something(else)\n' ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, [b'#! something\n', b'f# coding=utf-8\n']) @@ -1347,7 +1351,7 @@ def test_mismatched_bom_and_cookie_second_line_raises_syntaxerror(self): b'do_something(else)\n' ) readline = self.get_readline(lines) - self.assertRaises(SyntaxError, detect_encoding, readline) + self.assertRaises(SyntaxError, tokenize.detect_encoding, readline) def test_cookie_second_line_noncommented_first_line(self): lines = ( @@ -1355,7 +1359,7 @@ def test_cookie_second_line_noncommented_first_line(self): b'# vim: set fileencoding=iso8859-15 :\n', b"print('\xe2\x82\xac')\n" ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'utf-8') expected = [b"print('\xc2\xa3')\n"] self.assertEqual(consumed_lines, expected) @@ -1366,7 +1370,7 @@ def test_cookie_second_line_commented_first_line(self): b'# vim: set fileencoding=iso8859-15 :\n', b"print('\xe2\x82\xac')\n" ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'iso8859-15') expected = [b"#print('\xc2\xa3')\n", b'# vim: set fileencoding=iso8859-15 :\n'] self.assertEqual(consumed_lines, expected) @@ -1377,7 +1381,7 @@ def test_cookie_second_line_empty_first_line(self): b'# vim: set fileencoding=iso8859-15 :\n', b"print('\xe2\x82\xac')\n" ) - encoding, consumed_lines = detect_encoding(self.get_readline(lines)) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(lines)) self.assertEqual(encoding, 'iso8859-15') expected = [b'\n', b'# vim: set fileencoding=iso8859-15 :\n'] self.assertEqual(consumed_lines, expected) @@ -1394,7 +1398,7 @@ def test_latin1_normalization(self): b"print(things)\n", b"do_something += 4\n") rl = self.get_readline(lines) - found, consumed_lines = detect_encoding(rl) + found, consumed_lines = tokenize.detect_encoding(rl) self.assertEqual(found, "iso-8859-1") def test_syntaxerror_latin1(self): @@ -1404,7 +1408,7 @@ def test_syntaxerror_latin1(self): b'print("\xdf")', # Latin-1: LATIN SMALL LETTER SHARP S ) readline = self.get_readline(lines) - self.assertRaises(SyntaxError, detect_encoding, readline) + self.assertRaises(SyntaxError, tokenize.detect_encoding, readline) def test_utf8_normalization(self): @@ -1417,36 +1421,36 @@ def test_utf8_normalization(self): b"# coding: " + enc.encode("ascii") + b"\n", b"1 + 3\n") rl = self.get_readline(lines) - found, consumed_lines = detect_encoding(rl) + found, consumed_lines = tokenize.detect_encoding(rl) self.assertEqual(found, "utf-8") def test_short_files(self): readline = self.get_readline((b'print(something)\n',)) - encoding, consumed_lines = detect_encoding(readline) + encoding, consumed_lines = tokenize.detect_encoding(readline) self.assertEqual(encoding, 'utf-8') self.assertEqual(consumed_lines, [b'print(something)\n']) - encoding, consumed_lines = detect_encoding(self.get_readline(())) + encoding, consumed_lines = tokenize.detect_encoding(self.get_readline(())) self.assertEqual(encoding, 'utf-8') self.assertEqual(consumed_lines, []) readline = self.get_readline((b'\xef\xbb\xbfprint(something)\n',)) - encoding, consumed_lines = detect_encoding(readline) + encoding, consumed_lines = tokenize.detect_encoding(readline) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, [b'print(something)\n']) readline = self.get_readline((b'\xef\xbb\xbf',)) - encoding, consumed_lines = detect_encoding(readline) + encoding, consumed_lines = tokenize.detect_encoding(readline) self.assertEqual(encoding, 'utf-8-sig') self.assertEqual(consumed_lines, []) readline = self.get_readline((b'# coding: bad\n',)) - self.assertRaises(SyntaxError, detect_encoding, readline) + self.assertRaises(SyntaxError, tokenize.detect_encoding, readline) def test_false_encoding(self): # Issue 18873: "Encoding" detected in non-comment lines readline = self.get_readline((b'print("#coding=fake")',)) - encoding, consumed_lines = detect_encoding(readline) + encoding, consumed_lines = tokenize.detect_encoding(readline) self.assertEqual(encoding, 'utf-8') self.assertEqual(consumed_lines, [b'print("#coding=fake")']) @@ -1459,14 +1463,14 @@ def test_open(self): with open(filename, 'w', encoding=encoding) as fp: print("# coding: %s" % encoding, file=fp) print("print('euro:\u20ac')", file=fp) - with tokenize_open(filename) as fp: + with tokenize.open(filename) as fp: self.assertEqual(fp.encoding, encoding) self.assertEqual(fp.mode, 'r') # test BOM (no coding cookie) with open(filename, 'w', encoding='utf-8-sig') as fp: print("print('euro:\u20ac')", file=fp) - with tokenize_open(filename) as fp: + with tokenize.open(filename) as fp: self.assertEqual(fp.encoding, 'utf-8-sig') self.assertEqual(fp.mode, 'r') @@ -1493,16 +1497,16 @@ def readline(self): ins = Bunk(lines, path) # Make sure lacking a name isn't an issue. del ins.name - detect_encoding(ins.readline) + tokenize.detect_encoding(ins.readline) with self.assertRaisesRegex(SyntaxError, '.*{}'.format(path)): ins = Bunk(lines, path) - detect_encoding(ins.readline) + tokenize.detect_encoding(ins.readline) def test_open_error(self): # Issue #23840: open() must close the binary file on error m = BytesIO(b'#coding:xxx') with mock.patch('tokenize._builtin_open', return_value=m): - self.assertRaises(SyntaxError, tokenize_open, 'foobar') + self.assertRaises(SyntaxError, tokenize.open, 'foobar') self.assertTrue(m.closed) @@ -1542,7 +1546,7 @@ def mock_readline(): tokenize_module.detect_encoding = mock_detect_encoding tokenize_module._generate_tokens_from_c_tokenizer = mock__tokenize try: - results = tokenize(mock_readline) + results = tokenize.tokenize(mock_readline) self.assertEqual(list(results)[1:], [b'first', b'second', b'1', b'2', b'3', b'4']) finally: @@ -1559,23 +1563,23 @@ def test_oneline_defs(self): buf = '\n'.join(buf) # Test that 500 consequent, one-line defs is OK - toks = list(tokenize(BytesIO(buf.encode('utf-8')).readline)) + toks = list(tokenize.tokenize(BytesIO(buf.encode('utf-8')).readline)) self.assertEqual(toks[-3].string, 'OK') # [-1] is always ENDMARKER # [-2] is always NEWLINE def assertExactTypeEqual(self, opstr, *optypes): - tokens = list(tokenize(BytesIO(opstr.encode('utf-8')).readline)) + tokens = list(tokenize.tokenize(BytesIO(opstr.encode('utf-8')).readline)) num_optypes = len(optypes) self.assertEqual(len(tokens), 3 + num_optypes) - self.assertEqual(tok_name[tokens[0].exact_type], - tok_name[ENCODING]) + self.assertEqual(tokenize.tok_name[tokens[0].exact_type], + tokenize.tok_name[tokenize.ENCODING]) for i in range(num_optypes): - self.assertEqual(tok_name[tokens[i + 1].exact_type], - tok_name[optypes[i]]) - self.assertEqual(tok_name[tokens[1 + num_optypes].exact_type], - tok_name[token.NEWLINE]) - self.assertEqual(tok_name[tokens[2 + num_optypes].exact_type], - tok_name[token.ENDMARKER]) + self.assertEqual(tokenize.tok_name[tokens[i + 1].exact_type], + tokenize.tok_name[optypes[i]]) + self.assertEqual(tokenize.tok_name[tokens[1 + num_optypes].exact_type], + tokenize.tok_name[token.NEWLINE]) + self.assertEqual(tokenize.tok_name[tokens[2 + num_optypes].exact_type], + tokenize.tok_name[token.ENDMARKER]) def test_exact_type(self): self.assertExactTypeEqual('()', token.LPAR, token.RPAR) @@ -1625,11 +1629,11 @@ def test_exact_type(self): self.assertExactTypeEqual('@=', token.ATEQUAL) self.assertExactTypeEqual('a**2+b**2==c**2', - NAME, token.DOUBLESTAR, NUMBER, + tokenize.NAME, token.DOUBLESTAR, tokenize.NUMBER, token.PLUS, - NAME, token.DOUBLESTAR, NUMBER, + tokenize.NAME, token.DOUBLESTAR, tokenize.NUMBER, token.EQEQUAL, - NAME, token.DOUBLESTAR, NUMBER) + tokenize.NAME, token.DOUBLESTAR, tokenize.NUMBER) self.assertExactTypeEqual('{1, 2, 3}', token.LBRACE, token.NUMBER, token.COMMA, @@ -1650,32 +1654,32 @@ def test_comment_at_the_end_of_the_source_without_newline(self): # See http://bugs.python.org/issue44667 source = 'b = 1\n\n#test' expected_tokens = [ - TokenInfo(type=token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), - TokenInfo(type=token.NAME, string='b', start=(1, 0), end=(1, 1), line='b = 1\n'), - TokenInfo(type=token.OP, string='=', start=(1, 2), end=(1, 3), line='b = 1\n'), - TokenInfo(type=token.NUMBER, string='1', start=(1, 4), end=(1, 5), line='b = 1\n'), - TokenInfo(type=token.NEWLINE, string='\n', start=(1, 5), end=(1, 6), line='b = 1\n'), - TokenInfo(type=token.NL, string='\n', start=(2, 0), end=(2, 1), line='\n'), - TokenInfo(type=token.COMMENT, string='#test', start=(3, 0), end=(3, 5), line='#test'), - TokenInfo(type=token.NL, string='', start=(3, 5), end=(3, 6), line='#test'), - TokenInfo(type=token.ENDMARKER, string='', start=(4, 0), end=(4, 0), line='') + tokenize.TokenInfo(type=token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), + tokenize.TokenInfo(type=token.NAME, string='b', start=(1, 0), end=(1, 1), line='b = 1\n'), + tokenize.TokenInfo(type=token.OP, string='=', start=(1, 2), end=(1, 3), line='b = 1\n'), + tokenize.TokenInfo(type=token.NUMBER, string='1', start=(1, 4), end=(1, 5), line='b = 1\n'), + tokenize.TokenInfo(type=token.NEWLINE, string='\n', start=(1, 5), end=(1, 6), line='b = 1\n'), + tokenize.TokenInfo(type=token.NL, string='\n', start=(2, 0), end=(2, 1), line='\n'), + tokenize.TokenInfo(type=token.COMMENT, string='#test', start=(3, 0), end=(3, 5), line='#test'), + tokenize.TokenInfo(type=token.NL, string='', start=(3, 5), end=(3, 6), line='#test'), + tokenize.TokenInfo(type=token.ENDMARKER, string='', start=(4, 0), end=(4, 0), line='') ] - tokens = list(tokenize(BytesIO(source.encode('utf-8')).readline)) + tokens = list(tokenize.tokenize(BytesIO(source.encode('utf-8')).readline)) self.assertEqual(tokens, expected_tokens) def test_newline_and_space_at_the_end_of_the_source_without_newline(self): # See https://github.com/python/cpython/issues/105435 source = 'a\n ' expected_tokens = [ - TokenInfo(token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), - TokenInfo(token.NAME, string='a', start=(1, 0), end=(1, 1), line='a\n'), - TokenInfo(token.NEWLINE, string='\n', start=(1, 1), end=(1, 2), line='a\n'), - TokenInfo(token.NL, string='', start=(2, 1), end=(2, 2), line=' '), - TokenInfo(token.ENDMARKER, string='', start=(3, 0), end=(3, 0), line='') + tokenize.TokenInfo(token.ENCODING, string='utf-8', start=(0, 0), end=(0, 0), line=''), + tokenize.TokenInfo(token.NAME, string='a', start=(1, 0), end=(1, 1), line='a\n'), + tokenize.TokenInfo(token.NEWLINE, string='\n', start=(1, 1), end=(1, 2), line='a\n'), + tokenize.TokenInfo(token.NL, string='', start=(2, 1), end=(2, 2), line=' '), + tokenize.TokenInfo(token.ENDMARKER, string='', start=(3, 0), end=(3, 0), line='') ] - tokens = list(tokenize(BytesIO(source.encode('utf-8')).readline)) + tokens = list(tokenize.tokenize(BytesIO(source.encode('utf-8')).readline)) self.assertEqual(tokens, expected_tokens) def test_invalid_character_in_fstring_middle(self): @@ -1695,7 +1699,7 @@ class UntokenizeTest(TestCase): def test_bad_input_order(self): # raise if previous row - u = Untokenizer() + u = tokenize.Untokenizer() u.prev_row = 2 u.prev_col = 2 with self.assertRaises(ValueError) as cm: @@ -1707,7 +1711,7 @@ def test_bad_input_order(self): def test_backslash_continuation(self): # The problem is that \ leaves no token - u = Untokenizer() + u = tokenize.Untokenizer() u.prev_row = 1 u.prev_col = 1 u.tokens = [] @@ -1719,17 +1723,17 @@ def test_backslash_continuation(self): TestRoundtrip.check_roundtrip(self, 'a\n b\n c\n \\\n c\n') def test_iter_compat(self): - u = Untokenizer() - token = (NAME, 'Hello') - tokens = [(ENCODING, 'utf-8'), token] + u = tokenize.Untokenizer() + token = (tokenize.NAME, 'Hello') + tokens = [(tokenize.ENCODING, 'utf-8'), token] u.compat(token, iter([])) self.assertEqual(u.tokens, ["Hello "]) - u = Untokenizer() + u = tokenize.Untokenizer() self.assertEqual(u.untokenize(iter([token])), 'Hello ') - u = Untokenizer() + u = tokenize.Untokenizer() self.assertEqual(u.untokenize(iter(tokens)), 'Hello ') self.assertEqual(u.encoding, 'utf-8') - self.assertEqual(untokenize(iter(tokens)), b'Hello ') + self.assertEqual(tokenize.untokenize(iter(tokens)), b'Hello ') class TestRoundtrip(TestCase): @@ -1752,17 +1756,17 @@ def check_roundtrip(self, f): else: code = f.read() readline = iter(code.splitlines(keepends=True)).__next__ - tokens5 = list(tokenize(readline)) + tokens5 = list(tokenize.tokenize(readline)) tokens2 = [tok[:2] for tok in tokens5] # Reproduce tokens2 from pairs - bytes_from2 = untokenize(tokens2) + bytes_from2 = tokenize.untokenize(tokens2) readline2 = iter(bytes_from2.splitlines(keepends=True)).__next__ - tokens2_from2 = [tok[:2] for tok in tokenize(readline2)] + tokens2_from2 = [tok[:2] for tok in tokenize.tokenize(readline2)] self.assertEqual(tokens2_from2, tokens2) # Reproduce tokens2 from 5-tuples - bytes_from5 = untokenize(tokens5) + bytes_from5 = tokenize.untokenize(tokens5) readline5 = iter(bytes_from5.splitlines(keepends=True)).__next__ - tokens2_from5 = [tok[:2] for tok in tokenize(readline5)] + tokens2_from5 = [tok[:2] for tok in tokenize.tokenize(readline5)] self.assertEqual(tokens2_from5, tokens2) def check_line_extraction(self, f): @@ -1771,8 +1775,8 @@ def check_line_extraction(self, f): else: code = f.read() readline = iter(code.splitlines(keepends=True)).__next__ - for tok in tokenize(readline): - if tok.type in {ENCODING, ENDMARKER}: + for tok in tokenize.tokenize(readline): + if tok.type in {tokenize.ENCODING, tokenize.ENDMARKER}: continue self.assertEqual(tok.string, tok.line[tok.start[1]: tok.end[1]]) @@ -1878,7 +1882,7 @@ def test_random_files(self): def roundtrip(self, code): if isinstance(code, str): code = code.encode('utf-8') - return untokenize(tokenize(BytesIO(code).readline)).decode('utf-8') + return tokenize.untokenize(tokenize.tokenize(BytesIO(code).readline)).decode('utf-8') def test_indentation_semantics_retained(self): """ @@ -1896,27 +1900,27 @@ def test_number_followed_by_name(self): # See issue #gh-105549 source = "2sin(x)" expected_tokens = [ - TokenInfo(type=token.NUMBER, string='2', start=(1, 0), end=(1, 1), line='2sin(x)'), - TokenInfo(type=token.NAME, string='sin', start=(1, 1), end=(1, 4), line='2sin(x)'), - TokenInfo(type=token.OP, string='(', start=(1, 4), end=(1, 5), line='2sin(x)'), - TokenInfo(type=token.NAME, string='x', start=(1, 5), end=(1, 6), line='2sin(x)'), - TokenInfo(type=token.OP, string=')', start=(1, 6), end=(1, 7), line='2sin(x)'), - TokenInfo(type=token.NEWLINE, string='', start=(1, 7), end=(1, 8), line='2sin(x)'), - TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + tokenize.TokenInfo(type=token.NUMBER, string='2', start=(1, 0), end=(1, 1), line='2sin(x)'), + tokenize.TokenInfo(type=token.NAME, string='sin', start=(1, 1), end=(1, 4), line='2sin(x)'), + tokenize.TokenInfo(type=token.OP, string='(', start=(1, 4), end=(1, 5), line='2sin(x)'), + tokenize.TokenInfo(type=token.NAME, string='x', start=(1, 5), end=(1, 6), line='2sin(x)'), + tokenize.TokenInfo(type=token.OP, string=')', start=(1, 6), end=(1, 7), line='2sin(x)'), + tokenize.TokenInfo(type=token.NEWLINE, string='', start=(1, 7), end=(1, 8), line='2sin(x)'), + tokenize.TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') ] - tokens = list(generate_tokens(StringIO(source).readline)) + tokens = list(tokenize.generate_tokens(StringIO(source).readline)) self.assertEqual(tokens, expected_tokens) def test_number_starting_with_zero(self): source = "01234" expected_tokens = [ - TokenInfo(type=token.NUMBER, string='01234', start=(1, 0), end=(1, 5), line='01234'), - TokenInfo(type=token.NEWLINE, string='', start=(1, 5), end=(1, 6), line='01234'), - TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + tokenize.TokenInfo(type=token.NUMBER, string='01234', start=(1, 0), end=(1, 5), line='01234'), + tokenize.TokenInfo(type=token.NEWLINE, string='', start=(1, 5), end=(1, 6), line='01234'), + tokenize.TokenInfo(type=token.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') ] - tokens = list(generate_tokens(StringIO(source).readline)) + tokens = list(tokenize.generate_tokens(StringIO(source).readline)) self.assertEqual(tokens, expected_tokens) class CTokenizeTest(TestCase): @@ -1926,7 +1930,7 @@ def check_tokenize(self, s, expected): f = StringIO(s) with self.subTest(source=s): result = stringify_tokens_from_source( - _generate_tokens_from_c_tokenizer(f.readline), s + tokenize._generate_tokens_from_c_tokenizer(f.readline), s ) self.assertEqual(result, expected.rstrip().splitlines()) @@ -1935,15 +1939,15 @@ def readline(encoding): yield "1+1".encode(encoding) expected = [ - TokenInfo(type=NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1'), - TokenInfo(type=OP, string='+', start=(1, 1), end=(1, 2), line='1+1'), - TokenInfo(type=NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1'), - TokenInfo(type=NEWLINE, string='', start=(1, 3), end=(1, 4), line='1+1'), - TokenInfo(type=ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') + tokenize.TokenInfo(type=tokenize.NUMBER, string='1', start=(1, 0), end=(1, 1), line='1+1'), + tokenize.TokenInfo(type=tokenize.OP, string='+', start=(1, 1), end=(1, 2), line='1+1'), + tokenize.TokenInfo(type=tokenize.NUMBER, string='1', start=(1, 2), end=(1, 3), line='1+1'), + tokenize.TokenInfo(type=tokenize.NEWLINE, string='', start=(1, 3), end=(1, 4), line='1+1'), + tokenize.TokenInfo(type=tokenize.ENDMARKER, string='', start=(2, 0), end=(2, 0), line='') ] for encoding in ["utf-8", "latin-1", "utf-16"]: with self.subTest(encoding=encoding): - tokens = list(_generate_tokens_from_c_tokenizer( + tokens = list(tokenize._generate_tokens_from_c_tokenizer( readline(encoding).__next__, extra_tokens=True, encoding=encoding, @@ -2796,7 +2800,7 @@ def test_unicode(self): def test_invalid_syntax(self): def get_tokens(string): the_string = StringIO(string) - return list(_generate_tokens_from_c_tokenizer(the_string.readline)) + return list(tokenize._generate_tokens_from_c_tokenizer(the_string.readline)) for case in [ "(1+2]", @@ -2832,7 +2836,7 @@ def get_tokens(string): "]", ]: with self.subTest(case=case): - self.assertRaises(TokenError, get_tokens, case) + self.assertRaises(tokenize.TokenError, get_tokens, case) def test_max_indent(self): MAXINDENT = 100 @@ -2844,14 +2848,14 @@ def generate_source(indents): valid = generate_source(MAXINDENT - 1) the_input = StringIO(valid) - tokens = list(_generate_tokens_from_c_tokenizer(the_input.readline)) - self.assertEqual(tokens[-2].type, DEDENT) - self.assertEqual(tokens[-1].type, ENDMARKER) + tokens = list(tokenize._generate_tokens_from_c_tokenizer(the_input.readline)) + self.assertEqual(tokens[-2].type, tokenize.DEDENT) + self.assertEqual(tokens[-1].type, tokenize.ENDMARKER) compile(valid, "", "exec") invalid = generate_source(MAXINDENT) the_input = StringIO(invalid) - self.assertRaises(IndentationError, lambda: list(_generate_tokens_from_c_tokenizer(the_input.readline))) + self.assertRaises(IndentationError, lambda: list(tokenize._generate_tokens_from_c_tokenizer(the_input.readline))) self.assertRaises( IndentationError, compile, invalid, "", "exec" ) @@ -2860,7 +2864,7 @@ def test_continuation_lines_indentation(self): def get_tokens(string): the_string = StringIO(string) return [(kind, string) for (kind, string, *_) - in _generate_tokens_from_c_tokenizer(the_string.readline)] + in tokenize._generate_tokens_from_c_tokenizer(the_string.readline)] code = dedent(""" def fib(n): diff --git a/Lib/tokenize.py b/Lib/tokenize.py index 49e8144edddab7..c21876fb403d8f 100644 --- a/Lib/tokenize.py +++ b/Lib/tokenize.py @@ -41,7 +41,7 @@ import token __all__ = token.__all__ + ["tokenize", "generate_tokens", "detect_encoding", - "untokenize", "TokenInfo"] + "untokenize", "TokenInfo", "open", "TokenError"] del token class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')): @@ -162,8 +162,6 @@ def _compile(expr): class TokenError(Exception): pass -class StopTokenizing(Exception): pass - class Untokenizer: def __init__(self): From 7a56a4148c521969d64164d2776641f19e3ca9e8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 19 Jun 2023 16:13:11 +0200 Subject: [PATCH 084/446] gh-104212: Explain how to port imp code to importlib (#105905) --- Doc/whatsnew/3.12.rst | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8febb6cc86b6fe..1a50bce0b65e0b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1369,7 +1369,38 @@ Removed * The :mod:`!imp` module has been removed. (Contributed by Barry Warsaw in :gh:`98040`.) - * Replace ``imp.new_module(name)`` with ``types.ModuleType(name)``. + * Replace removed :mod:`!imp` functions with :mod:`importlib` functions: + + ================================= ======================================= + imp importlib + ================================= ======================================= + ``imp.NullImporter`` Insert ``None`` into ``sys.path_importer_cache`` + ``imp.cache_from_source()`` :func:`importlib.util.cache_from_source` + ``imp.find_module()`` :func:`importlib.util.find_spec` + ``imp.get_magic()`` :attr:`importlib.util.MAGIC_NUMBER` + ``imp.get_suffixes()`` :attr:`importlib.machinery.SOURCE_SUFFIXES`, :attr:`importlib.machinery.EXTENSION_SUFFIXES`, and :attr:`importlib.machinery.BYTECODE_SUFFIXES` + ``imp.get_tag()`` :attr:`sys.implementation.cache_tag ` + ``imp.load_module()`` :func:`importlib.import_module` + ``imp.new_module(name)`` ``types.ModuleType(name)`` + ``imp.reload()`` :func:`importlib.reload` + ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` + ================================= ======================================= + + * Removed :mod:`!imp` functions and attributes with no replacements: + + * undocumented functions: + + * ``imp.init_builtin()`` + * ``imp.load_compiled()`` + * ``imp.load_dynamic()`` + * ``imp.load_package()`` + * ``imp.load_source()`` + + * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: + the locking scheme has changed in Python 3.3 to per-module locks. + * ``imp.find_module()`` constants: ``SEARCH_ERROR``, ``PY_SOURCE``, + ``PY_COMPILED``, ``C_EXTENSION``, ``PY_RESOURCE``, ``PKG_DIRECTORY``, + ``C_BUILTIN``, ``PY_FROZEN``, ``PY_CODERESOURCE``, ``IMP_HOOK``. * Removed the ``suspicious`` rule from the documentation Makefile, and removed ``Doc/tools/rstlint.py``, both in favor of `sphinx-lint From 1858db7cbdbf41aa600c954c15224307bf81a258 Mon Sep 17 00:00:00 2001 From: "T. Wouters" Date: Mon, 19 Jun 2023 19:09:04 +0200 Subject: [PATCH 085/446] GH-105808: Fix a regression introduced in GH-101251 (#105910) Fix a regression introduced in pythonGH-101251, causing GzipFile.flush() to not flush the compressor (nor pass along the zip_mode argument). --- Lib/gzip.py | 3 +- Lib/test/test_gzip.py | 49 +++++++++++++++++++ ...-06-19-11-31-55.gh-issue-105808.NL-quu.rst | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst diff --git a/Lib/gzip.py b/Lib/gzip.py index 8796c8d9fd9a2d..cf8b675064ce89 100644 --- a/Lib/gzip.py +++ b/Lib/gzip.py @@ -370,8 +370,9 @@ def close(self): def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH): self._check_not_closed() if self.mode == WRITE: - # Ensure the compressor's buffer is flushed self._buffer.flush() + # Ensure the compressor's buffer is flushed + self.fileobj.write(self.compress.flush(zlib_mode)) self.fileobj.flush() def fileno(self): diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index 6de413e5056ef0..c7ac7c687c8b2d 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -9,6 +9,7 @@ import struct import sys import unittest +import zlib from subprocess import PIPE, Popen from test.support import import_helper from test.support import os_helper @@ -616,6 +617,54 @@ def test_issue44439(self): self.assertEqual(f.write(q), LENGTH) self.assertEqual(f.tell(), LENGTH) + def test_flush_flushes_compressor(self): + # See issue GH-105808. + b = io.BytesIO() + message = b"important message here." + with gzip.GzipFile(fileobj=b, mode='w') as f: + f.write(message) + f.flush() + partial_data = b.getvalue() + full_data = b.getvalue() + self.assertEqual(gzip.decompress(full_data), message) + # The partial data should contain the gzip header and the complete + # message, but not the end-of-stream markers (so we can't just + # decompress it directly). + with self.assertRaises(EOFError): + gzip.decompress(partial_data) + d = zlib.decompressobj(wbits=-zlib.MAX_WBITS) + f = io.BytesIO(partial_data) + gzip._read_gzip_header(f) + read_message = d.decompress(f.read()) + self.assertEqual(read_message, message) + + def test_flush_modes(self): + # Make sure the argument to flush is properly passed to the + # zlib.compressobj; see issue GH-105808. + class FakeCompressor: + def __init__(self): + self.modes = [] + def compress(self, data): + return b'' + def flush(self, mode=-1): + self.modes.append(mode) + return b'' + b = io.BytesIO() + fc = FakeCompressor() + with gzip.GzipFile(fileobj=b, mode='w') as f: + f.compress = fc + f.flush() + f.flush(50) + f.flush(zlib_mode=100) + # The implicit close will also flush the compressor. + expected_modes = [ + zlib.Z_SYNC_FLUSH, + 50, + 100, + -1, + ] + self.assertEqual(fc.modes, expected_modes) + class TestOpen(BaseTest): def test_binary_modes(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst b/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst new file mode 100644 index 00000000000000..8e69fd627c28e8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-19-11-31-55.gh-issue-105808.NL-quu.rst @@ -0,0 +1 @@ +Fix a regression introduced in GH-101251 for 3.12, causing :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along the ``zip_mode`` argument). From 28187a9c4f95affe50fd37e0db0db177e2b9c2e9 Mon Sep 17 00:00:00 2001 From: Crowthebird <78076854+thatbirdguythatuknownot@users.noreply.github.com> Date: Tue, 20 Jun 2023 05:50:57 +0800 Subject: [PATCH 086/446] gh-105908: fix `barry_as_FLUFL` future import (#105909) --- Lib/test/test_future.py | 8 ++++++++ ...023-06-19-11-04-01.gh-issue-105908.7oanny.rst | 1 + Python/compile.c | 16 ++++++++++------ 3 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index b8b591a1bcf2c6..4730bfafbd9cfe 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -4,6 +4,7 @@ import ast import unittest from test.support import import_helper +from test.support.script_helper import spawn_python, kill_python from textwrap import dedent import os import re @@ -121,6 +122,13 @@ def test_unicode_literals_exec(self): exec("from __future__ import unicode_literals; x = ''", {}, scope) self.assertIsInstance(scope["x"], str) + def test_syntactical_future_repl(self): + p = spawn_python('-i') + p.stdin.write(b"from __future__ import barry_as_FLUFL\n") + p.stdin.write(b"2 <> 3\n") + out = kill_python(p) + self.assertNotIn(b'SyntaxError: invalid syntax', out) + class AnnotationsFutureTestCase(unittest.TestCase): template = dedent( """ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst new file mode 100644 index 00000000000000..03db3f064f503f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-19-11-04-01.gh-issue-105908.7oanny.rst @@ -0,0 +1 @@ +Fixed bug where :gh:`99111` breaks future import ``barry_as_FLUFL`` in the Python REPL. diff --git a/Python/compile.c b/Python/compile.c index cfa945ba7603bb..69468f755a1d26 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -494,8 +494,10 @@ static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone); static int compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, - PyCompilerFlags flags, int optimize, PyArena *arena) + PyCompilerFlags *flags, int optimize, PyArena *arena) { + PyCompilerFlags local_flags = _PyCompilerFlags_INIT; + c->c_const_cache = PyDict_New(); if (!c->c_const_cache) { return ERROR; @@ -511,10 +513,13 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, if (!_PyFuture_FromAST(mod, filename, &c->c_future)) { return ERROR; } - int merged = c->c_future.ff_features | flags.cf_flags; + if (!flags) { + flags = &local_flags; + } + int merged = c->c_future.ff_features | flags->cf_flags; c->c_future.ff_features = merged; - flags.cf_flags = merged; - c->c_flags = flags; + flags->cf_flags = merged; + c->c_flags = *flags; c->c_optimize = (optimize == -1) ? _Py_GetConfig()->optimization_level : optimize; c->c_nestlevel = 0; @@ -535,12 +540,11 @@ static struct compiler* new_compiler(mod_ty mod, PyObject *filename, PyCompilerFlags *pflags, int optimize, PyArena *arena) { - PyCompilerFlags flags = pflags ? *pflags : _PyCompilerFlags_INIT; struct compiler *c = PyMem_Calloc(1, sizeof(struct compiler)); if (c == NULL) { return NULL; } - if (compiler_setup(c, mod, filename, flags, optimize, arena) < 0) { + if (compiler_setup(c, mod, filename, pflags, optimize, arena) < 0) { compiler_free(c); return NULL; } From 33f0a8578b729e67c482daedc2660648afd0ee78 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 19 Jun 2023 23:47:04 +0100 Subject: [PATCH 087/446] gh-105481: generate _specializations and _specialized_instructions from bytecodes.c (#105913) --- Include/internal/pycore_opcode.h | 104 +++++++++++------------ Include/opcode.h | 108 ++++++++++++------------ Lib/_opcode_metadata.py | 94 +++++++++++++++++++++ Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 96 ++------------------- Makefile.pre.in | 1 + PCbuild/regen.targets | 2 +- Python/makeopcodetargets.py | 3 +- Python/opcode_targets.h | 104 +++++++++++------------ Python/stdlib_module_names.h | 1 + Tools/build/generate_opcode_h.py | 29 ++++--- Tools/cases_generator/generate_cases.py | 77 ++++++++++++++--- 12 files changed, 345 insertions(+), 277 deletions(-) create mode 100644 Lib/_opcode_metadata.py diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 5935823b7e24ad..6b269e3c02d6c1 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -241,49 +241,49 @@ static const char *const _PyOpcode_OpName[267] = { [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", [END_SEND] = "END_SEND", - [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [NOP] = "NOP", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [RESERVED] = "RESERVED", - [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", - [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [MAKE_FUNCTION] = "MAKE_FUNCTION", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [SEND_GEN] = "SEND_GEN", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [FORMAT_SIMPLE] = "FORMAT_SIMPLE", [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", - [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", - [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", - [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", + [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -291,39 +291,39 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", - [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [COMPARE_OP_INT] = "COMPARE_OP_INT", [COMPARE_OP_STR] = "COMPARE_OP_STR", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [GET_ITER] = "GET_ITER", - [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [FOR_ITER_GEN] = "FOR_ITER_GEN", - [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", - [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", - [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", - [RETURN_GENERATOR] = "RETURN_GENERATOR", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [LOAD_LOCALS] = "LOAD_LOCALS", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -346,9 +346,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -367,7 +367,7 @@ static const char *const _PyOpcode_OpName[267] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", @@ -383,20 +383,20 @@ static const char *const _PyOpcode_OpName[267] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", + [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", [CONVERT_VALUE] = "CONVERT_VALUE", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [SEND_GEN] = "SEND_GEN", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", diff --git a/Include/opcode.h b/Include/opcode.h index 43a18065cf08c2..39bb70a8f2842f 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -158,65 +158,65 @@ extern "C" { #define LOAD_ZERO_SUPER_ATTR 265 #define STORE_FAST_MAYBE_NULL 266 #define MAX_PSEUDO_OPCODE 266 -#define BINARY_OP_ADD_FLOAT 6 +#define BINARY_OP_MULTIPLY_INT 6 #define BINARY_OP_ADD_INT 7 -#define BINARY_OP_ADD_UNICODE 8 -#define BINARY_OP_INPLACE_ADD_UNICODE 10 -#define BINARY_OP_MULTIPLY_FLOAT 13 -#define BINARY_OP_MULTIPLY_INT 14 -#define BINARY_OP_SUBTRACT_FLOAT 16 -#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_OP_SUBTRACT_INT 8 +#define BINARY_OP_MULTIPLY_FLOAT 10 +#define BINARY_OP_ADD_FLOAT 13 +#define BINARY_OP_SUBTRACT_FLOAT 14 +#define BINARY_OP_ADD_UNICODE 16 +#define BINARY_OP_INPLACE_ADD_UNICODE 18 #define BINARY_SUBSCR_DICT 19 #define BINARY_SUBSCR_GETITEM 20 #define BINARY_SUBSCR_LIST_INT 21 #define BINARY_SUBSCR_TUPLE_INT 22 -#define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 28 -#define CALL_BOUND_METHOD_EXACT_ARGS 29 -#define CALL_BUILTIN_CLASS 34 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 38 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 39 -#define CALL_NO_KW_BUILTIN_FAST 42 -#define CALL_NO_KW_BUILTIN_O 43 -#define CALL_NO_KW_ISINSTANCE 44 -#define CALL_NO_KW_LEN 45 -#define CALL_NO_KW_LIST_APPEND 46 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 47 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 48 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 56 -#define CALL_NO_KW_STR_1 57 -#define CALL_NO_KW_TUPLE_1 58 -#define CALL_NO_KW_TYPE_1 59 -#define COMPARE_OP_FLOAT 62 -#define COMPARE_OP_INT 63 -#define COMPARE_OP_STR 64 -#define FOR_ITER_LIST 65 -#define FOR_ITER_TUPLE 66 -#define FOR_ITER_RANGE 67 -#define FOR_ITER_GEN 70 -#define LOAD_SUPER_ATTR_ATTR 72 -#define LOAD_SUPER_ATTR_METHOD 73 -#define LOAD_ATTR_CLASS 76 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 77 -#define LOAD_ATTR_INSTANCE_VALUE 78 -#define LOAD_ATTR_MODULE 79 -#define LOAD_ATTR_PROPERTY 80 -#define LOAD_ATTR_SLOT 81 -#define LOAD_ATTR_WITH_HINT 82 -#define LOAD_ATTR_METHOD_LAZY_DICT 84 -#define LOAD_ATTR_METHOD_NO_DICT 86 -#define LOAD_ATTR_METHOD_WITH_VALUES 88 -#define LOAD_GLOBAL_BUILTIN 111 -#define LOAD_GLOBAL_MODULE 112 -#define STORE_ATTR_INSTANCE_VALUE 113 -#define STORE_ATTR_SLOT 132 -#define STORE_ATTR_WITH_HINT 148 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 155 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 -#define SEND_GEN 161 +#define STORE_SUBSCR_DICT 23 +#define STORE_SUBSCR_LIST_INT 28 +#define SEND_GEN 29 +#define UNPACK_SEQUENCE_TWO_TUPLE 34 +#define UNPACK_SEQUENCE_TUPLE 38 +#define UNPACK_SEQUENCE_LIST 39 +#define STORE_ATTR_INSTANCE_VALUE 42 +#define STORE_ATTR_SLOT 43 +#define STORE_ATTR_WITH_HINT 44 +#define LOAD_GLOBAL_MODULE 45 +#define LOAD_GLOBAL_BUILTIN 46 +#define LOAD_SUPER_ATTR_ATTR 47 +#define LOAD_SUPER_ATTR_METHOD 48 +#define LOAD_ATTR_INSTANCE_VALUE 56 +#define LOAD_ATTR_MODULE 57 +#define LOAD_ATTR_WITH_HINT 58 +#define LOAD_ATTR_SLOT 59 +#define LOAD_ATTR_CLASS 62 +#define LOAD_ATTR_PROPERTY 63 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 64 +#define LOAD_ATTR_METHOD_WITH_VALUES 65 +#define LOAD_ATTR_METHOD_NO_DICT 66 +#define LOAD_ATTR_METHOD_LAZY_DICT 67 +#define COMPARE_OP_FLOAT 70 +#define COMPARE_OP_INT 72 +#define COMPARE_OP_STR 73 +#define FOR_ITER_LIST 76 +#define FOR_ITER_TUPLE 77 +#define FOR_ITER_RANGE 78 +#define FOR_ITER_GEN 79 +#define CALL_BOUND_METHOD_EXACT_ARGS 80 +#define CALL_PY_EXACT_ARGS 81 +#define CALL_PY_WITH_DEFAULTS 82 +#define CALL_NO_KW_TYPE_1 84 +#define CALL_NO_KW_STR_1 86 +#define CALL_NO_KW_TUPLE_1 88 +#define CALL_BUILTIN_CLASS 111 +#define CALL_NO_KW_BUILTIN_O 112 +#define CALL_NO_KW_BUILTIN_FAST 113 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 132 +#define CALL_NO_KW_LEN 148 +#define CALL_NO_KW_ISINSTANCE 153 +#define CALL_NO_KW_LIST_APPEND 154 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 155 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 159 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 160 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 161 #define NB_ADD 0 #define NB_AND 1 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py new file mode 100644 index 00000000000000..92ed4037d8ddb7 --- /dev/null +++ b/Lib/_opcode_metadata.py @@ -0,0 +1,94 @@ +# This file is generated by Tools/cases_generator/generate_cases.py +# from: +# Python/bytecodes.c +# Do not edit! + +_specializations = { + "BINARY_OP": [ + "BINARY_OP_MULTIPLY_INT", + "BINARY_OP_ADD_INT", + "BINARY_OP_SUBTRACT_INT", + "BINARY_OP_MULTIPLY_FLOAT", + "BINARY_OP_ADD_FLOAT", + "BINARY_OP_SUBTRACT_FLOAT", + "BINARY_OP_ADD_UNICODE", + ], + "BINARY_SUBSCR": [ + "BINARY_SUBSCR_DICT", + "BINARY_SUBSCR_GETITEM", + "BINARY_SUBSCR_LIST_INT", + "BINARY_SUBSCR_TUPLE_INT", + ], + "STORE_SUBSCR": [ + "STORE_SUBSCR_DICT", + "STORE_SUBSCR_LIST_INT", + ], + "SEND": [ + "SEND_GEN", + ], + "UNPACK_SEQUENCE": [ + "UNPACK_SEQUENCE_TWO_TUPLE", + "UNPACK_SEQUENCE_TUPLE", + "UNPACK_SEQUENCE_LIST", + ], + "STORE_ATTR": [ + "STORE_ATTR_INSTANCE_VALUE", + "STORE_ATTR_SLOT", + "STORE_ATTR_WITH_HINT", + ], + "LOAD_GLOBAL": [ + "LOAD_GLOBAL_MODULE", + "LOAD_GLOBAL_BUILTIN", + ], + "LOAD_SUPER_ATTR": [ + "LOAD_SUPER_ATTR_ATTR", + "LOAD_SUPER_ATTR_METHOD", + ], + "LOAD_ATTR": [ + "LOAD_ATTR_INSTANCE_VALUE", + "LOAD_ATTR_MODULE", + "LOAD_ATTR_WITH_HINT", + "LOAD_ATTR_SLOT", + "LOAD_ATTR_CLASS", + "LOAD_ATTR_PROPERTY", + "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + "LOAD_ATTR_METHOD_WITH_VALUES", + "LOAD_ATTR_METHOD_NO_DICT", + "LOAD_ATTR_METHOD_LAZY_DICT", + ], + "COMPARE_OP": [ + "COMPARE_OP_FLOAT", + "COMPARE_OP_INT", + "COMPARE_OP_STR", + ], + "FOR_ITER": [ + "FOR_ITER_LIST", + "FOR_ITER_TUPLE", + "FOR_ITER_RANGE", + "FOR_ITER_GEN", + ], + "CALL": [ + "CALL_BOUND_METHOD_EXACT_ARGS", + "CALL_PY_EXACT_ARGS", + "CALL_PY_WITH_DEFAULTS", + "CALL_NO_KW_TYPE_1", + "CALL_NO_KW_STR_1", + "CALL_NO_KW_TUPLE_1", + "CALL_BUILTIN_CLASS", + "CALL_NO_KW_BUILTIN_O", + "CALL_NO_KW_BUILTIN_FAST", + "CALL_BUILTIN_FAST_WITH_KEYWORDS", + "CALL_NO_KW_LEN", + "CALL_NO_KW_ISINSTANCE", + "CALL_NO_KW_LIST_APPEND", + "CALL_NO_KW_METHOD_DESCRIPTOR_O", + "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + ], +} + +# An irregular case: +_specializations["BINARY_OP"].append("BINARY_OP_INPLACE_ADD_UNICODE") + +_specialized_instructions = [opcode for family in _specializations.values() for opcode in family] diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index cf68c448a6e4ec..6a3eabe1973ac8 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -450,6 +450,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.13a1 3552 (Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST) # Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE) # Python 3.13a1 3554 (more efficient bytecodes for f-strings) +# Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c) # Python 3.14 will start with 3600 @@ -466,7 +467,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 = (3554).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3555).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 71a8afad43fc6f..ed01d2cdad9ebf 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -21,6 +21,12 @@ except ImportError: pass +# _opcode_metadata may not be ready during early stages of the build +try: + from _opcode_metadata import _specializations, _specialized_instructions +except ModuleNotFoundError: + pass + cmp_op = ('<', '<=', '==', '!=', '>', '>=') hasarg = [] @@ -348,96 +354,6 @@ def pseudo_op(name, op, real_ops): "INTRINSIC_SET_FUNCTION_TYPE_PARAMS", ] -_specializations = { - "BINARY_OP": [ - "BINARY_OP_ADD_FLOAT", - "BINARY_OP_ADD_INT", - "BINARY_OP_ADD_UNICODE", - "BINARY_OP_INPLACE_ADD_UNICODE", - "BINARY_OP_MULTIPLY_FLOAT", - "BINARY_OP_MULTIPLY_INT", - "BINARY_OP_SUBTRACT_FLOAT", - "BINARY_OP_SUBTRACT_INT", - ], - "BINARY_SUBSCR": [ - "BINARY_SUBSCR_DICT", - "BINARY_SUBSCR_GETITEM", - "BINARY_SUBSCR_LIST_INT", - "BINARY_SUBSCR_TUPLE_INT", - ], - "CALL": [ - "CALL_PY_EXACT_ARGS", - "CALL_PY_WITH_DEFAULTS", - "CALL_BOUND_METHOD_EXACT_ARGS", - "CALL_BUILTIN_CLASS", - "CALL_BUILTIN_FAST_WITH_KEYWORDS", - "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", - "CALL_NO_KW_BUILTIN_FAST", - "CALL_NO_KW_BUILTIN_O", - "CALL_NO_KW_ISINSTANCE", - "CALL_NO_KW_LEN", - "CALL_NO_KW_LIST_APPEND", - "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", - "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - "CALL_NO_KW_METHOD_DESCRIPTOR_O", - "CALL_NO_KW_STR_1", - "CALL_NO_KW_TUPLE_1", - "CALL_NO_KW_TYPE_1", - ], - "COMPARE_OP": [ - "COMPARE_OP_FLOAT", - "COMPARE_OP_INT", - "COMPARE_OP_STR", - ], - "FOR_ITER": [ - "FOR_ITER_LIST", - "FOR_ITER_TUPLE", - "FOR_ITER_RANGE", - "FOR_ITER_GEN", - ], - "LOAD_SUPER_ATTR": [ - "LOAD_SUPER_ATTR_ATTR", - "LOAD_SUPER_ATTR_METHOD", - ], - "LOAD_ATTR": [ - # These potentially push [NULL, bound method] onto the stack. - "LOAD_ATTR_CLASS", - "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - "LOAD_ATTR_INSTANCE_VALUE", - "LOAD_ATTR_MODULE", - "LOAD_ATTR_PROPERTY", - "LOAD_ATTR_SLOT", - "LOAD_ATTR_WITH_HINT", - # These will always push [unbound method, self] onto the stack. - "LOAD_ATTR_METHOD_LAZY_DICT", - "LOAD_ATTR_METHOD_NO_DICT", - "LOAD_ATTR_METHOD_WITH_VALUES", - ], - "LOAD_GLOBAL": [ - "LOAD_GLOBAL_BUILTIN", - "LOAD_GLOBAL_MODULE", - ], - "STORE_ATTR": [ - "STORE_ATTR_INSTANCE_VALUE", - "STORE_ATTR_SLOT", - "STORE_ATTR_WITH_HINT", - ], - "STORE_SUBSCR": [ - "STORE_SUBSCR_DICT", - "STORE_SUBSCR_LIST_INT", - ], - "UNPACK_SEQUENCE": [ - "UNPACK_SEQUENCE_LIST", - "UNPACK_SEQUENCE_TUPLE", - "UNPACK_SEQUENCE_TWO_TUPLE", - ], - "SEND": [ - "SEND_GEN", - ], -} -_specialized_instructions = [ - opcode for family in _specializations.values() for opcode in family -] _cache_format = { "LOAD_GLOBAL": { diff --git a/Makefile.pre.in b/Makefile.pre.in index a9c53bae4bf63c..3a404b0d16403f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1425,6 +1425,7 @@ regen-opcode: # using Tools/build/generate_opcode_h.py $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_opcode_h.py \ $(srcdir)/Lib/opcode.py \ + $(srcdir)/Lib/_opcode_metadata.py \ $(srcdir)/Include/opcode.h.new \ $(srcdir)/Include/internal/pycore_opcode.h.new \ $(srcdir)/Include/internal/pycore_intrinsics.h.new diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets index 15f3d1375a10a2..e9e16a15f94cce 100644 --- a/PCbuild/regen.targets +++ b/PCbuild/regen.targets @@ -59,7 +59,7 @@ Inputs="@(_OpcodeSources)" Outputs="@(_OpcodeOutputs)" DependsOnTargets="FindPythonForBuild"> - diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py index 2b402ae0b6a031..5843079b729936 100755 --- a/Python/makeopcodetargets.py +++ b/Python/makeopcodetargets.py @@ -25,12 +25,13 @@ def write_contents(f): """Write C code contents to the target file object. """ opcode = find_module('opcode') + _opcode_metadata = find_module('_opcode_metadata') targets = ['_unknown_opcode'] * 256 for opname, op in opcode.opmap.items(): if not opcode.is_pseudo(op): targets[op] = "TARGET_%s" % opname next_op = 1 - for opname in opcode._specialized_instructions: + for opname in _opcode_metadata._specialized_instructions: while targets[next_op] != '_unknown_opcode': next_op += 1 targets[next_op] = "TARGET_%s" % opname diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 451d8bbd17fa63..4de4bf0608f35e 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -5,49 +5,49 @@ static void *opcode_targets[256] = { &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, &&TARGET_END_SEND, - &&TARGET_BINARY_OP_ADD_FLOAT, + &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_ADD_UNICODE, + &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_NOP, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, - &&TARGET_BINARY_OP_MULTIPLY_INT, - &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_RESERVED, - &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, - &&TARGET_CALL_PY_EXACT_ARGS, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_MAKE_FUNCTION, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, - &&TARGET_CALL_PY_WITH_DEFAULTS, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_SEND_GEN, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_BUILTIN_CLASS, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_FORMAT_SIMPLE, &&TARGET_FORMAT_WITH_SPEC, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, - &&TARGET_CALL_NO_KW_BUILTIN_O, - &&TARGET_CALL_NO_KW_ISINSTANCE, - &&TARGET_CALL_NO_KW_LEN, - &&TARGET_CALL_NO_KW_LIST_APPEND, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_SUPER_ATTR_ATTR, + &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, - &&TARGET_CALL_NO_KW_STR_1, - &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, + &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_GET_ITER, + &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_COMPARE_OP_FLOAT, + &&TARGET_LOAD_BUILD_CLASS, &&TARGET_COMPARE_OP_INT, &&TARGET_COMPARE_OP_STR, + &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_RETURN_GENERATOR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, - &&TARGET_GET_ITER, - &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_FOR_ITER_GEN, - &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_SUPER_ATTR_ATTR, - &&TARGET_LOAD_SUPER_ATTR_METHOD, - &&TARGET_LOAD_ASSERTION_ERROR, - &&TARGET_RETURN_GENERATOR, - &&TARGET_LOAD_ATTR_CLASS, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_LOAD_ATTR_PROPERTY, - &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_PY_EXACT_ARGS, + &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_RETURN_VALUE, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_CALL_NO_KW_STR_1, &&TARGET_LOAD_LOCALS, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, - &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_CALL_BUILTIN_CLASS, + &&TARGET_CALL_NO_KW_BUILTIN_O, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,7 +131,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_STORE_ATTR_SLOT, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, @@ -147,20 +147,20 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_CALL_NO_KW_LEN, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, - &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_CALL_NO_KW_ISINSTANCE, + &&TARGET_CALL_NO_KW_LIST_APPEND, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_CONVERT_VALUE, - &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, - &&TARGET_SEND_GEN, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index 925b8b3230fce3..13b1764f0886d1 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -47,6 +47,7 @@ static const char* _Py_stdlib_module_names[] = { "_multibytecodec", "_multiprocessing", "_opcode", +"_opcode_metadata", "_operator", "_osx_support", "_overlapped", diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index ec9fdae56128c0..4711fbbd1eb8c3 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -66,18 +66,22 @@ UINT32_MASK = (1<<32)-1 +def get_python_module_dict(filename): + mod = {} + with tokenize.open(filename) as fp: + code = fp.read() + exec(code, mod) + return mod -def main(opcode_py, outfile='Include/opcode.h', +def main(opcode_py, + _opcode_metadata_py='Lib/_opcode_metadata.py', + outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h', intrinsicoutfile='Include/internal/pycore_intrinsics.h'): - opcode = {} - if hasattr(tokenize, 'open'): - fp = tokenize.open(opcode_py) # Python 3.2+ - else: - fp = open(opcode_py) # Python 2.7 - with fp: - code = fp.read() - exec(code, opcode) + + _opcode_metadata = get_python_module_dict(_opcode_metadata_py) + + opcode = get_python_module_dict(opcode_py) opmap = opcode['opmap'] opname = opcode['opname'] hasarg = opcode['hasarg'] @@ -87,6 +91,7 @@ def main(opcode_py, outfile='Include/opcode.h', is_pseudo = opcode['is_pseudo'] _pseudo_ops = opcode['_pseudo_ops'] + ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"] @@ -101,7 +106,7 @@ def main(opcode_py, outfile='Include/opcode.h', specialized_opmap = {} opname_including_specialized = opname.copy() - for name in opcode['_specialized_instructions']: + for name in _opcode_metadata['_specialized_instructions']: while used[next_op]: next_op += 1 specialized_opmap[name] = next_op @@ -145,7 +150,7 @@ def main(opcode_py, outfile='Include/opcode.h', for basic, op in opmap.items(): if not is_pseudo(op): deoptcodes[basic] = basic - for basic, family in opcode["_specializations"].items(): + for basic, family in _opcode_metadata["_specializations"].items(): for specialized in family: deoptcodes[specialized] = basic iobj.write("\nconst uint8_t _PyOpcode_Deopt[256] = {\n") @@ -203,4 +208,4 @@ def main(opcode_py, outfile='Include/opcode.h', if __name__ == '__main__': - main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]) + main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 723996bd8f7696..e4ccd38bac4b49 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -26,6 +26,9 @@ DEFAULT_METADATA_OUTPUT = os.path.relpath( os.path.join(ROOT, "Python/opcode_metadata.h") ) +DEFAULT_PYMETADATA_OUTPUT = os.path.relpath( + os.path.join(ROOT, "Lib/_opcode_metadata.py") +) BEGIN_MARKER = "// BEGIN BYTECODES //" END_MARKER = "// END BYTECODES //" RE_PREDICTED = ( @@ -47,7 +50,10 @@ "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT ) arg_parser.add_argument( - "-m", "--metadata", type=str, help="Generated metadata", default=DEFAULT_METADATA_OUTPUT + "-m", "--metadata", type=str, help="Generated C metadata", default=DEFAULT_METADATA_OUTPUT +) +arg_parser.add_argument( + "-p", "--pymetadata", type=str, help="Generated Python metadata", default=DEFAULT_PYMETADATA_OUTPUT ) arg_parser.add_argument( "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" @@ -121,11 +127,13 @@ class Formatter: nominal_filename: str def __init__( - self, stream: typing.TextIO, indent: int, emit_line_directives: bool = False + self, stream: typing.TextIO, indent: int, + emit_line_directives: bool = False, comment: str = "//", ) -> None: self.stream = stream self.prefix = " " * indent self.emit_line_directives = emit_line_directives + self.comment = comment self.lineno = 1 filename = os.path.relpath(self.stream.name, ROOT) # Make filename more user-friendly and less platform-specific @@ -519,14 +527,17 @@ class Analyzer: input_filenames: list[str] output_filename: str metadata_filename: str + pymetadata_filename: str errors: int = 0 emit_line_directives: bool = False - def __init__(self, input_filenames: list[str], output_filename: str, metadata_filename: str): + def __init__(self, input_filenames: list[str], output_filename: str, + metadata_filename: str, pymetadata_filename: str): """Read the input file.""" self.input_filenames = input_filenames self.output_filename = output_filename self.metadata_filename = metadata_filename + self.pymetadata_filename = pymetadata_filename def error(self, msg: str, node: parser.Node) -> None: lineno = 0 @@ -1005,11 +1016,16 @@ def write_function( self.out.emit("") def from_source_files(self) -> str: - paths = "\n// ".join( + paths = f"\n{self.out.comment} ".join( os.path.relpath(filename, ROOT).replace(os.path.sep, posixpath.sep) for filename in self.input_filenames ) - return f"// from:\n// {paths}\n" + return f"{self.out.comment} from:\n{self.out.comment} {paths}\n" + + def write_provenance_header(self): + self.out.write_raw(f"{self.out.comment} This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"{self.out.comment} Do not edit!\n") def write_metadata(self) -> None: """Write instruction metadata to output file.""" @@ -1043,10 +1059,7 @@ def write_metadata(self) -> None: # Create formatter self.out = Formatter(f, 0) - # Write provenance header - self.out.write_raw(f"// This file is generated by {THIS}\n") - self.out.write_raw(self.from_source_files()) - self.out.write_raw(f"// Do not edit!\n") + self.write_provenance_header() self.write_pseudo_instrs() @@ -1100,6 +1113,39 @@ def write_metadata(self) -> None: self.out.emit("};") self.out.emit("#endif") + with open(self.pymetadata_filename, "w") as f: + # Create formatter + self.out = Formatter(f, 0, comment = "#") + + self.write_provenance_header() + + self.out.emit("") + self.out.emit("_specializations = {") + for name, family in self.families.items(): + assert len(family.members) > 1 + with self.out.indent(): + self.out.emit(f"\"{family.members[0]}\": [") + with self.out.indent(): + for m in family.members[1:]: + self.out.emit(f"\"{m}\",") + self.out.emit(f"],") + self.out.emit("}") + + # Handle special case + self.out.emit("") + self.out.emit("# An irregular case:") + self.out.emit( + "_specializations[\"BINARY_OP\"].append(" + "\"BINARY_OP_INPLACE_ADD_UNICODE\")") + + # Make list of specialized instructions + self.out.emit("") + self.out.emit( + "_specialized_instructions = [" + "opcode for family in _specializations.values() for opcode in family" + "]") + + def write_pseudo_instrs(self) -> None: """Write the IS_PSEUDO_INSTR macro""" self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) \\") @@ -1134,9 +1180,9 @@ def write_instructions(self) -> None: self.out = Formatter(f, 8, self.emit_line_directives) # Write provenance header - self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(f"{self.out.comment} This file is generated by {THIS}\n") self.out.write_raw(self.from_source_files()) - self.out.write_raw(f"// Do not edit!\n") + self.out.write_raw(f"{self.out.comment} Do not edit!\n") # Write and count instructions of all kinds n_instrs = 0 @@ -1168,13 +1214,13 @@ def write_overridden_instr_place_holder(self, place_holder: OverriddenInstructionPlaceHolder) -> None: self.out.emit("") self.out.emit( - f"// TARGET({place_holder.name}) overridden by later definition") + f"{self.out.comment} TARGET({place_holder.name}) overridden by later definition") def write_instr(self, instr: Instruction) -> None: name = instr.name self.out.emit("") if instr.inst.override: - self.out.emit("// Override") + self.out.emit("{self.out.comment} Override") with self.out.block(f"TARGET({name})"): if instr.predicted: self.out.emit(f"PREDICTED({name});") @@ -1315,7 +1361,10 @@ def main(): args = arg_parser.parse_args() # Prints message and sys.exit(2) on error if len(args.input) == 0: args.input.append(DEFAULT_INPUT) - a = Analyzer(args.input, args.output, args.metadata) # Raises OSError if input unreadable + + # Raises OSError if input unreadable + a = Analyzer(args.input, args.output, args.metadata, args.pymetadata) + if args.emit_line_directives: a.emit_line_directives = True a.parse() # Raises SyntaxError on failure From a5c2ad0c3d23d2b1e61ab8e0d7ee64f7e1288547 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 00:55:23 +0200 Subject: [PATCH 088/446] gh-105922: Refactor PyRun_InteractiveOneObjectEx() (#105925) Refactor PyRun_InteractiveOneObjectEx(), _PyRun_SimpleFileObject() and PyRun_SimpleStringFlags(): * Keep a strong reference to the __main__ module while using its dictionary (PyModule_GetDict()). Use PyImport_AddModule() with Py_XNewRef(). * Declare variables closer to where they are defined. * Rename variables to use name longer than 1 character. * Add pyrun_one_parse_ast() sub-function. --- Python/pythonrun.c | 182 +++++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 74 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 05e7b4370869af..f9e798ebcd6596 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -179,90 +179,118 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag } -/* A PyRun_InteractiveOneObject() auxiliary function that does not print the - * error on failure. */ +// Call _PyParser_ASTFromFile() with sys.stdin.encoding, sys.ps1 and sys.ps2 static int -PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, - PyCompilerFlags *flags) +pyrun_one_parse_ast(FILE *fp, PyObject *filename, + PyCompilerFlags *flags, PyArena *arena, mod_ty *pmod) { - PyObject *m, *d, *v, *w, *oenc = NULL; - mod_ty mod; - PyArena *arena; - const char *ps1 = "", *ps2 = "", *enc = NULL; - int errcode = 0; PyThreadState *tstate = _PyThreadState_GET(); + // Get sys.stdin.encoding (as UTF-8) + PyObject *attr; // borrowed ref + PyObject *encoding_obj = NULL; + const char *encoding = NULL; if (fp == stdin) { - /* Fetch encoding from sys.stdin if possible. */ - v = _PySys_GetAttr(tstate, &_Py_ID(stdin)); - if (v && v != Py_None) { - oenc = PyObject_GetAttr(v, &_Py_ID(encoding)); - if (oenc) - enc = PyUnicode_AsUTF8(oenc); - if (!enc) - PyErr_Clear(); + attr = _PySys_GetAttr(tstate, &_Py_ID(stdin)); + if (attr && attr != Py_None) { + encoding_obj = PyObject_GetAttr(attr, &_Py_ID(encoding)); + if (encoding_obj) { + encoding = PyUnicode_AsUTF8(encoding_obj); + if (!encoding) { + PyErr_Clear(); + } + } } } - v = _PySys_GetAttr(tstate, &_Py_ID(ps1)); - if (v != NULL) { - v = PyObject_Str(v); - if (v == NULL) + + // Get sys.ps1 (as UTF-8) + attr = _PySys_GetAttr(tstate, &_Py_ID(ps1)); + PyObject *ps1_obj = NULL; + const char *ps1 = ""; + if (attr != NULL) { + ps1_obj = PyObject_Str(attr); + if (ps1_obj == NULL) { PyErr_Clear(); - else if (PyUnicode_Check(v)) { - ps1 = PyUnicode_AsUTF8(v); + } + else if (PyUnicode_Check(ps1_obj)) { + ps1 = PyUnicode_AsUTF8(ps1_obj); if (ps1 == NULL) { PyErr_Clear(); ps1 = ""; } } } - w = _PySys_GetAttr(tstate, &_Py_ID(ps2)); - if (w != NULL) { - w = PyObject_Str(w); - if (w == NULL) + + // Get sys.ps2 (as UTF-8) + attr = _PySys_GetAttr(tstate, &_Py_ID(ps2)); + PyObject *ps2_obj = NULL; + const char *ps2 = ""; + if (attr != NULL) { + ps2_obj = PyObject_Str(attr); + if (ps2_obj == NULL) { PyErr_Clear(); - else if (PyUnicode_Check(w)) { - ps2 = PyUnicode_AsUTF8(w); + } + else if (PyUnicode_Check(ps2_obj)) { + ps2 = PyUnicode_AsUTF8(ps2_obj); if (ps2 == NULL) { PyErr_Clear(); ps2 = ""; } } } - arena = _PyArena_New(); - if (arena == NULL) { - Py_XDECREF(v); - Py_XDECREF(w); - Py_XDECREF(oenc); - return -1; - } - - mod = _PyParser_ASTFromFile(fp, filename, enc, Py_single_input, - ps1, ps2, flags, &errcode, arena); - Py_XDECREF(v); - Py_XDECREF(w); - Py_XDECREF(oenc); - if (mod == NULL) { - _PyArena_Free(arena); + int errcode = 0; + *pmod = _PyParser_ASTFromFile(fp, filename, encoding, + Py_single_input, ps1, ps2, + flags, &errcode, arena); + Py_XDECREF(ps1_obj); + Py_XDECREF(ps2_obj); + Py_XDECREF(encoding_obj); + + if (*pmod == NULL) { if (errcode == E_EOF) { PyErr_Clear(); return E_EOF; } return -1; } - m = PyImport_AddModuleObject(&_Py_ID(__main__)); - if (m == NULL) { + return 0; +} + + +/* A PyRun_InteractiveOneObject() auxiliary function that does not print the + * error on failure. */ +static int +PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, + PyCompilerFlags *flags) +{ + PyArena *arena = _PyArena_New(); + if (arena == NULL) { + return -1; + } + + mod_ty mod; + int parse_res = pyrun_one_parse_ast(fp, filename, flags, arena, &mod); + if (parse_res != 0) { + _PyArena_Free(arena); + return parse_res; + } + + PyObject *main_module = Py_XNewRef(PyImport_AddModuleObject(&_Py_ID(__main__))); + if (main_module == NULL) { _PyArena_Free(arena); return -1; } - d = PyModule_GetDict(m); - v = run_mod(mod, filename, d, d, flags, arena); + PyObject *main_dict = PyModule_GetDict(main_module); // borrowed ref + + PyObject *res = run_mod(mod, filename, main_dict, main_dict, flags, arena); _PyArena_Free(arena); - if (v == NULL) { + Py_DECREF(main_module); + if (res == NULL) { return -1; } - Py_DECREF(v); + Py_DECREF(res); + flush_io(); return 0; } @@ -376,22 +404,22 @@ int _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags) { - PyObject *m, *d, *v; - int set_file_name = 0, ret = -1; + int ret = -1; - m = PyImport_AddModule("__main__"); - if (m == NULL) + PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__")); + if (main_module == NULL) return -1; - Py_INCREF(m); - d = PyModule_GetDict(m); - if (_PyDict_GetItemStringWithError(d, "__file__") == NULL) { + PyObject *dict = PyModule_GetDict(main_module); // borrowed ref + + int set_file_name = 0; + if (_PyDict_GetItemStringWithError(dict, "__file__") == NULL) { if (PyErr_Occurred()) { goto done; } - if (PyDict_SetItemString(d, "__file__", filename) < 0) { + if (PyDict_SetItemString(dict, "__file__", filename) < 0) { goto done; } - if (PyDict_SetItemString(d, "__cached__", Py_None) < 0) { + if (PyDict_SetItemString(dict, "__cached__", Py_None) < 0) { goto done; } set_file_name = 1; @@ -402,6 +430,7 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, goto done; } + PyObject *v; if (pyc) { FILE *pyc_fp; /* Try to run a pyc file. First, re-open in binary */ @@ -415,42 +444,43 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, goto done; } - if (set_main_loader(d, filename, "SourcelessFileLoader") < 0) { + if (set_main_loader(dict, filename, "SourcelessFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; fclose(pyc_fp); goto done; } - v = run_pyc_file(pyc_fp, d, d, flags); + v = run_pyc_file(pyc_fp, dict, dict, flags); } else { /* When running from stdin, leave __main__.__loader__ alone */ if (PyUnicode_CompareWithASCIIString(filename, "") != 0 && - set_main_loader(d, filename, "SourceFileLoader") < 0) { + set_main_loader(dict, filename, "SourceFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; goto done; } - v = pyrun_file(fp, filename, Py_file_input, d, d, + v = pyrun_file(fp, filename, Py_file_input, dict, dict, closeit, flags); } flush_io(); if (v == NULL) { - Py_CLEAR(m); + Py_CLEAR(main_module); PyErr_Print(); goto done; } Py_DECREF(v); ret = 0; + done: if (set_file_name) { - if (PyDict_DelItemString(d, "__file__")) { + if (PyDict_DelItemString(dict, "__file__")) { PyErr_Clear(); } - if (PyDict_DelItemString(d, "__cached__")) { + if (PyDict_DelItemString(dict, "__cached__")) { PyErr_Clear(); } } - Py_XDECREF(m); + Py_XDECREF(main_module); return ret; } @@ -472,17 +502,21 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) { - PyObject *m, *d, *v; - m = PyImport_AddModule("__main__"); - if (m == NULL) + PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__")); + if (main_module == NULL) { return -1; - d = PyModule_GetDict(m); - v = PyRun_StringFlags(command, Py_file_input, d, d, flags); - if (v == NULL) { + } + PyObject *dict = PyModule_GetDict(main_module); // borrowed ref + + PyObject *res = PyRun_StringFlags(command, Py_file_input, + dict, dict, flags); + Py_DECREF(main_module); + if (res == NULL) { PyErr_Print(); return -1; } - Py_DECREF(v); + + Py_DECREF(res); return 0; } From 7f97c8e367869e2aebe9f28bc5f8d4ce36448878 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 01:31:17 +0200 Subject: [PATCH 089/446] gh-105927: Refactor weakrefobject.c (#105928) * Rename proxy_checkref() to proxy_check_ref(). * proxy_check_ref() now checks the object, not the proxy. * Most functions take PyObject* instead of PyWeakReference*. * Remove redundant calls to PyWeakref_GET_OBJECT(). --- Objects/weakrefobject.c | 116 +++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index aee79fc1410b29..4e18fce9a35ecb 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -19,7 +19,7 @@ _PyWeakref_GetWeakrefCount(PyWeakReference *head) return count; } -static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames); +static PyObject *weakref_vectorcall(PyObject *self, PyObject *const *args, size_t nargsf, PyObject *kwnames); static void init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback) @@ -29,7 +29,7 @@ init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback) self->wr_prev = NULL; self->wr_next = NULL; self->wr_callback = Py_XNewRef(callback); - self->vectorcall = (vectorcallfunc)weakref_vectorcall; + self->vectorcall = weakref_vectorcall; } static PyWeakReference * @@ -129,7 +129,7 @@ gc_clear(PyWeakReference *self) static PyObject * -weakref_vectorcall(PyWeakReference *self, PyObject *const *args, +weakref_vectorcall(PyObject *self, PyObject *const *args, size_t nargsf, PyObject *kwnames) { if (!_PyArg_NoKwnames("weakref", kwnames)) { @@ -160,7 +160,7 @@ weakref_hash(PyWeakReference *self) static PyObject * -weakref_repr(PyWeakReference *self) +weakref_repr(PyObject *self) { PyObject *name, *repr; PyObject* obj = PyWeakref_GET_OBJECT(self); @@ -174,17 +174,12 @@ weakref_repr(PyWeakReference *self) if (name == NULL || !PyUnicode_Check(name)) { repr = PyUnicode_FromFormat( "", - self, - Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name, - obj); + self, Py_TYPE(obj)->tp_name, obj); } else { repr = PyUnicode_FromFormat( "", - self, - Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name, - obj, - name); + self, Py_TYPE(obj)->tp_name, obj, name); } Py_DECREF(obj); Py_XDECREF(name); @@ -203,8 +198,9 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) !PyWeakref_Check(other)) { Py_RETURN_NOTIMPLEMENTED; } - if (PyWeakref_GET_OBJECT(self) == Py_None - || PyWeakref_GET_OBJECT(other) == Py_None) { + PyObject* obj = PyWeakref_GET_OBJECT(self); + PyObject* other_obj = PyWeakref_GET_OBJECT(other); + if (obj == Py_None || other_obj == Py_None) { int res = (self == other); if (op == Py_NE) res = !res; @@ -213,8 +209,6 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) else Py_RETURN_FALSE; } - PyObject* obj = PyWeakref_GET_OBJECT(self); - PyObject* other_obj = PyWeakref_GET_OBJECT(other); Py_INCREF(obj); Py_INCREF(other_obj); PyObject* res = PyObject_RichCompare(obj, other_obj, op); @@ -372,7 +366,7 @@ _PyWeakref_RefType = { .tp_dealloc = weakref_dealloc, .tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall), .tp_call = PyVectorcall_Call, - .tp_repr = (reprfunc)weakref_repr, + .tp_repr = weakref_repr, .tp_hash = (hashfunc)weakref_hash, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE, @@ -388,15 +382,15 @@ _PyWeakref_RefType = { }; -static int -proxy_checkref(PyWeakReference *proxy) +static bool +proxy_check_ref(PyObject *obj) { - if (PyWeakref_GET_OBJECT(proxy) == Py_None) { + if (obj == Py_None) { PyErr_SetString(PyExc_ReferenceError, "weakly-referenced object no longer exists"); - return 0; + return false; } - return 1; + return true; } @@ -406,9 +400,9 @@ proxy_checkref(PyWeakReference *proxy) */ #define UNWRAP(o) \ if (PyWeakref_CheckProxy(o)) { \ - if (!proxy_checkref((PyWeakReference *)o)) \ - return NULL; \ o = PyWeakref_GET_OBJECT(o); \ + if (!proxy_check_ref(o)) \ + return NULL; \ } #define WRAP_UNARY(method, generic) \ @@ -483,11 +477,12 @@ proxy_repr(PyWeakReference *proxy) static int -proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value) +proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value) { - if (!proxy_checkref(proxy)) - return -1; PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return -1; + } Py_INCREF(obj); int res = PyObject_SetAttr(obj, name, value); Py_DECREF(obj); @@ -539,10 +534,10 @@ WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply) WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply) static int -proxy_bool(PyWeakReference *proxy) +proxy_bool(PyObject *proxy) { PyObject *o = PyWeakref_GET_OBJECT(proxy); - if (!proxy_checkref(proxy)) { + if (!proxy_check_ref(o)) { return -1; } Py_INCREF(o); @@ -564,12 +559,12 @@ proxy_dealloc(PyWeakReference *self) /* sequence slots */ static int -proxy_contains(PyWeakReference *proxy, PyObject *value) +proxy_contains(PyObject *proxy, PyObject *value) { - if (!proxy_checkref(proxy)) - return -1; - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return -1; + } Py_INCREF(obj); int res = PySequence_Contains(obj, value); Py_DECREF(obj); @@ -579,12 +574,12 @@ proxy_contains(PyWeakReference *proxy, PyObject *value) /* mapping slots */ static Py_ssize_t -proxy_length(PyWeakReference *proxy) +proxy_length(PyObject *proxy) { - if (!proxy_checkref(proxy)) - return -1; - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return -1; + } Py_INCREF(obj); Py_ssize_t res = PyObject_Length(obj); Py_DECREF(obj); @@ -594,12 +589,12 @@ proxy_length(PyWeakReference *proxy) WRAP_BINARY(proxy_getitem, PyObject_GetItem) static int -proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value) +proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value) { - if (!proxy_checkref(proxy)) - return -1; - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return -1; + } Py_INCREF(obj); int res; if (value == NULL) { @@ -614,11 +609,12 @@ proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value) /* iterator slots */ static PyObject * -proxy_iter(PyWeakReference *proxy) +proxy_iter(PyObject *proxy) { - if (!proxy_checkref(proxy)) - return NULL; PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return NULL; + } Py_INCREF(obj); PyObject* res = PyObject_GetIter(obj); Py_DECREF(obj); @@ -626,12 +622,12 @@ proxy_iter(PyWeakReference *proxy) } static PyObject * -proxy_iternext(PyWeakReference *proxy) +proxy_iternext(PyObject *proxy) { - if (!proxy_checkref(proxy)) - return NULL; - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + if (!proxy_check_ref(obj)) { + return NULL; + } if (!PyIter_Check(obj)) { PyErr_Format(PyExc_TypeError, "Weakref proxy referenced a non-iterator '%.200s' object", @@ -666,7 +662,7 @@ static PyNumberMethods proxy_as_number = { proxy_neg, /*nb_negative*/ proxy_pos, /*nb_positive*/ proxy_abs, /*nb_absolute*/ - (inquiry)proxy_bool, /*nb_bool*/ + proxy_bool, /*nb_bool*/ proxy_invert, /*nb_invert*/ proxy_lshift, /*nb_lshift*/ proxy_rshift, /*nb_rshift*/ @@ -696,20 +692,20 @@ static PyNumberMethods proxy_as_number = { }; static PySequenceMethods proxy_as_sequence = { - (lenfunc)proxy_length, /*sq_length*/ + proxy_length, /*sq_length*/ 0, /*sq_concat*/ 0, /*sq_repeat*/ 0, /*sq_item*/ 0, /*sq_slice*/ 0, /*sq_ass_item*/ - 0, /*sq_ass_slice*/ - (objobjproc)proxy_contains, /* sq_contains */ + 0, /*sq_ass_slice*/ + proxy_contains, /* sq_contains */ }; static PyMappingMethods proxy_as_mapping = { - (lenfunc)proxy_length, /*mp_length*/ + proxy_length, /*mp_length*/ proxy_getitem, /*mp_subscript*/ - (objobjargproc)proxy_setitem, /*mp_ass_subscript*/ + proxy_setitem, /*mp_ass_subscript*/ }; @@ -734,7 +730,7 @@ _PyWeakref_ProxyType = { 0, /* tp_call */ proxy_str, /* tp_str */ proxy_getattr, /* tp_getattro */ - (setattrofunc)proxy_setattr, /* tp_setattro */ + proxy_setattr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ @@ -742,9 +738,9 @@ _PyWeakref_ProxyType = { (inquiry)gc_clear, /* tp_clear */ proxy_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_iter, /* tp_iter */ - (iternextfunc)proxy_iternext, /* tp_iternext */ - proxy_methods, /* tp_methods */ + proxy_iter, /* tp_iter */ + proxy_iternext, /* tp_iternext */ + proxy_methods, /* tp_methods */ }; @@ -768,7 +764,7 @@ _PyWeakref_CallableProxyType = { proxy_call, /* tp_call */ proxy_str, /* tp_str */ proxy_getattr, /* tp_getattro */ - (setattrofunc)proxy_setattr, /* tp_setattro */ + proxy_setattr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ @@ -776,8 +772,8 @@ _PyWeakref_CallableProxyType = { (inquiry)gc_clear, /* tp_clear */ proxy_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_iter, /* tp_iter */ - (iternextfunc)proxy_iternext, /* tp_iternext */ + proxy_iter, /* tp_iter */ + proxy_iternext, /* tp_iternext */ }; From 03f1a132eeb34c738812161947ef171b21d58c25 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 08:48:14 +0200 Subject: [PATCH 090/446] gh-105922: Add PyImport_AddModuleRef() function (#105923) * Add tests on PyImport_AddModuleRef(), PyImport_AddModule() and PyImport_AddModuleObject(). * pythonrun.c: Replace Py_XNewRef(PyImport_AddModule(name)) with PyImport_AddModuleRef(name). --- Doc/c-api/import.rst | 37 +++++++++----- Doc/data/refcounts.dat | 3 ++ Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.13.rst | 5 ++ Include/import.h | 5 ++ Lib/test/test_import/__init__.py | 24 ++++++++++ Lib/test/test_stable_abi_ctypes.py | 1 + ...-06-19-20-02-16.gh-issue-105922.o4T6wO.rst | 3 ++ Misc/stable_abi.toml | 2 + Modules/_testcapimodule.c | 48 +++++++++++++++++++ PC/python3dll.c | 1 + Python/import.c | 39 +++++++++++---- Python/pythonrun.c | 4 +- 13 files changed, 149 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-19-20-02-16.gh-issue-105922.o4T6wO.rst diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 6db20237f3fdb0..7aacc219a2bd61 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -98,27 +98,40 @@ Importing Modules an exception set on failure (the module still exists in this case). -.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name) +.. c:function:: PyObject* PyImport_AddModuleRef(const char *name) + + Return the module object corresponding to a module name. + + The *name* argument may be of the form ``package.module``. First check the + modules dictionary if there's one there, and if not, create a new one and + insert it in the modules dictionary. + + Return a :term:`strong reference` to the module on success. Return ``NULL`` + with an exception set on failure. - Return the module object corresponding to a module name. The *name* argument - may be of the form ``package.module``. First check the modules dictionary if - there's one there, and if not, create a new one and insert it in the modules - dictionary. Return ``NULL`` with an exception set on failure. + The module name *name* is decoded from UTF-8. - .. note:: + This function does not load or import the module; if the module wasn't + already loaded, you will get an empty module object. Use + :c:func:`PyImport_ImportModule` or one of its variants to import a module. + Package structures implied by a dotted name for *name* are not created if + not already present. + + .. versionadded:: 3.13 + + +.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name) - This function does not load or import the module; if the module wasn't already - loaded, you will get an empty module object. Use :c:func:`PyImport_ImportModule` - or one of its variants to import a module. Package structures implied by a - dotted name for *name* are not created if not already present. + Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed + reference` and *name* is a Python :class:`str` object. .. versionadded:: 3.3 .. c:function:: PyObject* PyImport_AddModule(const char *name) - Similar to :c:func:`PyImport_AddModuleObject`, but the name is a UTF-8 - encoded string instead of a Unicode object. + Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed + reference`. .. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index f5628abb90443c..d707cc34c98c97 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -974,6 +974,9 @@ PyCoro_New:PyFrameObject*:frame:0: PyCoro_New:PyObject*:name:0: PyCoro_New:PyObject*:qualname:0: +PyImport_AddModuleRef:PyObject*::+1: +PyImport_AddModuleRef:const char*:name:: + PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules PyImport_AddModule:const char*:name:: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 80806aedfcdbd5..a3fde01cf67f3c 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -298,6 +298,7 @@ type,PyGetSetDef,3.2,,full-abi var,PyGetSetDescr_Type,3.2,, function,PyImport_AddModule,3.2,, function,PyImport_AddModuleObject,3.7,, +function,PyImport_AddModuleRef,3.13,, function,PyImport_AppendInittab,3.2,, function,PyImport_ExecCodeModule,3.2,, function,PyImport_ExecCodeModuleEx,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 735715f0152898..bbe02a9e85b42c 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -426,6 +426,11 @@ New Features APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats. (Contributed by Inada Naoki in :gh:`104922`.) +* Add :c:func:`PyImport_AddModuleRef`: similar to + :c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead + of a :term:`borrowed reference`. + (Contributed by Victor Stinner in :gh:`105922`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/import.h b/Include/import.h index 6c63744edb0634..24b23b9119196f 100644 --- a/Include/import.h +++ b/Include/import.h @@ -43,6 +43,11 @@ PyAPI_FUNC(PyObject *) PyImport_AddModuleObject( PyAPI_FUNC(PyObject *) PyImport_AddModule( const char *name /* UTF-8 encoded string */ ); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 +PyAPI_FUNC(PyObject *) PyImport_AddModuleRef( + const char *name /* UTF-8 encoded string */ + ); +#endif PyAPI_FUNC(PyObject *) PyImport_ImportModule( const char *name /* UTF-8 encoded string */ ); diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 71a50bcbeedf9b..f2726da203efbd 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -2621,6 +2621,30 @@ def test_basic_multiple_interpreters_reset_each(self): # * module's global state was initialized, not reset +@cpython_only +class CAPITests(unittest.TestCase): + def test_pyimport_addmodule(self): + # gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule() + # and PyImport_AddModuleObject() + import _testcapi + for name in ( + 'sys', # frozen module + 'test', # package + __name__, # package.module + ): + _testcapi.check_pyimport_addmodule(name) + + def test_pyimport_addmodule_create(self): + # gh-105922: Test PyImport_AddModuleRef(), create a new module + import _testcapi + name = 'dontexist' + self.assertNotIn(name, sys.modules) + self.addCleanup(unload, name) + + mod = _testcapi.check_pyimport_addmodule(name) + self.assertIs(mod, sys.modules[name]) + + if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. unittest.main() diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 8cad71c7c34545..c26dff5aaf370b 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -328,6 +328,7 @@ def test_windows_feature_macros(self): "PyGetSetDescr_Type", "PyImport_AddModule", "PyImport_AddModuleObject", + "PyImport_AddModuleRef", "PyImport_AppendInittab", "PyImport_ExecCodeModule", "PyImport_ExecCodeModuleEx", diff --git a/Misc/NEWS.d/next/C API/2023-06-19-20-02-16.gh-issue-105922.o4T6wO.rst b/Misc/NEWS.d/next/C API/2023-06-19-20-02-16.gh-issue-105922.o4T6wO.rst new file mode 100644 index 00000000000000..7515d684184e17 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-19-20-02-16.gh-issue-105922.o4T6wO.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyImport_AddModuleRef`: similar to :c:func:`PyImport_AddModule`, +but return a :term:`strong reference` instead of a :term:`borrowed reference`. +Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index f9100054175fc1..7025ed4e66b698 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2428,3 +2428,5 @@ added = '3.12' [const.Py_TPFLAGS_ITEMS_AT_END] added = '3.12' +[function.PyImport_AddModuleRef] + added = '3.13' diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 35687b49f24a0d..9d4517c8f68b09 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3325,6 +3325,53 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) } +static PyObject * +check_pyimport_addmodule(PyObject *self, PyObject *args) +{ + const char *name; + if (!PyArg_ParseTuple(args, "s", &name)) { + return NULL; + } + + // test PyImport_AddModuleRef() + PyObject *module = PyImport_AddModuleRef(name); + if (module == NULL) { + return NULL; + } + assert(PyModule_Check(module)); + // module is a strong reference + + // test PyImport_AddModule() + PyObject *module2 = PyImport_AddModule(name); + if (module2 == NULL) { + goto error; + } + assert(PyModule_Check(module2)); + assert(module2 == module); + // module2 is a borrowed ref + + // test PyImport_AddModuleObject() + PyObject *name_obj = PyUnicode_FromString(name); + if (name_obj == NULL) { + goto error; + } + PyObject *module3 = PyImport_AddModuleObject(name_obj); + Py_DECREF(name_obj); + if (module3 == NULL) { + goto error; + } + assert(PyModule_Check(module3)); + assert(module3 == module); + // module3 is a borrowed ref + + return module; + +error: + Py_DECREF(module); + return NULL; +} + + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3468,6 +3515,7 @@ static PyMethodDef TestMethods[] = { {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"test_atexit", test_atexit, METH_NOARGS}, + {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/PC/python3dll.c b/PC/python3dll.c index 505feef4b986c4..fea19b77185dd5 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -288,6 +288,7 @@ EXPORT_FUNC(PyGILState_GetThisThreadState) EXPORT_FUNC(PyGILState_Release) EXPORT_FUNC(PyImport_AddModule) EXPORT_FUNC(PyImport_AddModuleObject) +EXPORT_FUNC(PyImport_AddModuleRef) EXPORT_FUNC(PyImport_AppendInittab) EXPORT_FUNC(PyImport_ExecCodeModule) EXPORT_FUNC(PyImport_ExecCodeModuleEx) diff --git a/Python/import.c b/Python/import.c index 779af55347a614..969902afea1cd6 100644 --- a/Python/import.c +++ b/Python/import.c @@ -350,20 +350,38 @@ import_add_module(PyThreadState *tstate, PyObject *name) return m; } +PyObject * +PyImport_AddModuleRef(const char *name) +{ + PyObject *name_obj = PyUnicode_FromString(name); + if (name_obj == NULL) { + return NULL; + } + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *module = import_add_module(tstate, name_obj); + Py_DECREF(name_obj); + return module; +} + + PyObject * PyImport_AddModuleObject(PyObject *name) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *mod = import_add_module(tstate, name); - if (mod) { - PyObject *ref = PyWeakref_NewRef(mod, NULL); - Py_DECREF(mod); - if (ref == NULL) { - return NULL; - } - mod = PyWeakref_GetObject(ref); - Py_DECREF(ref); + if (!mod) { + return NULL; } + + // gh-86160: PyImport_AddModuleObject() returns a borrowed reference + PyObject *ref = PyWeakref_NewRef(mod, NULL); + Py_DECREF(mod); + if (ref == NULL) { + return NULL; + } + + mod = PyWeakref_GetObject(ref); + Py_DECREF(ref); return mod; /* borrowed reference */ } @@ -2240,11 +2258,12 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod) if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) { return -1; } - PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed + + PyObject *importlib = PyImport_AddModuleRef("_frozen_importlib"); if (importlib == NULL) { return -1; } - IMPORTLIB(interp) = Py_NewRef(importlib); + IMPORTLIB(interp) = importlib; // Import the _imp module if (verbose) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c index f9e798ebcd6596..af82fa491511c1 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -406,7 +406,7 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, { int ret = -1; - PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__")); + PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) return -1; PyObject *dict = PyModule_GetDict(main_module); // borrowed ref @@ -502,7 +502,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) { - PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__")); + PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { return -1; } From cb388c9a85a8dd6817ea7d969f53657002df6272 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 08:52:40 +0200 Subject: [PATCH 091/446] gh-105927: Add _PyWeakref_GET_REF() internal function (#105929) Add new pycore_weakref.h internal header file. --- Include/internal/pycore_weakref.h | 40 +++++++++++++ Makefile.pre.in | 1 + Objects/weakrefobject.c | 92 ++++++++++++++---------------- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + 5 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 Include/internal/pycore_weakref.h diff --git a/Include/internal/pycore_weakref.h b/Include/internal/pycore_weakref.h new file mode 100644 index 00000000000000..4e2b979c91928b --- /dev/null +++ b/Include/internal/pycore_weakref.h @@ -0,0 +1,40 @@ +#ifndef Py_INTERNAL_WEAKREF_H +#define Py_INTERNAL_WEAKREF_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) { + assert(PyWeakref_Check(ref_obj)); + PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); + PyObject *obj = ref->wr_object; + + if (obj == Py_None) { + // clear_weakref() was called + return NULL; + } + + // Explanation for the Py_REFCNT() check: when a weakref's target is part + // of a long chain of deallocations which triggers the trashcan mechanism, + // clearing the weakrefs can be delayed long after the target's refcount + // has dropped to zero. In the meantime, code accessing the weakref will + // be able to "see" the target object even though it is supposed to be + // unreachable. See issue gh-60806. + Py_ssize_t refcnt = Py_REFCNT(obj); + if (refcnt == 0) { + return NULL; + } + + assert(refcnt > 0); + return Py_NewRef(obj); +} + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_WEAKREF_H */ + diff --git a/Makefile.pre.in b/Makefile.pre.in index 3a404b0d16403f..e9a8d8ffb71fd2 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1801,6 +1801,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_unicodeobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject_generated.h \ $(srcdir)/Include/internal/pycore_warnings.h \ + $(srcdir)/Include/internal/pycore_weakref.h \ $(DTRACE_HEADERS) \ @PLATFORM_HEADERS@ \ \ diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 4e18fce9a35ecb..9995a7756570ca 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -1,5 +1,6 @@ #include "Python.h" #include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "structmember.h" // PyMemberDef @@ -147,12 +148,11 @@ weakref_hash(PyWeakReference *self) { if (self->hash != -1) return self->hash; - PyObject* obj = PyWeakref_GET_OBJECT(self); - if (obj == Py_None) { + PyObject* obj = _PyWeakref_GET_REF((PyObject*)self); + if (obj == NULL) { PyErr_SetString(PyExc_TypeError, "weak object has gone away"); return -1; } - Py_INCREF(obj); self->hash = PyObject_Hash(obj); Py_DECREF(obj); return self->hash; @@ -162,15 +162,13 @@ weakref_hash(PyWeakReference *self) static PyObject * weakref_repr(PyObject *self) { - PyObject *name, *repr; - PyObject* obj = PyWeakref_GET_OBJECT(self); - - if (obj == Py_None) { + PyObject* obj = _PyWeakref_GET_REF(self); + if (obj == NULL) { return PyUnicode_FromFormat("", self); } - Py_INCREF(obj); - name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__)); + PyObject *name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__)); + PyObject *repr; if (name == NULL || !PyUnicode_Check(name)) { repr = PyUnicode_FromFormat( "", @@ -191,16 +189,18 @@ weakref_repr(PyObject *self) gone away, they are equal if they are identical. */ static PyObject * -weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) +weakref_richcompare(PyObject* self, PyObject* other, int op) { if ((op != Py_EQ && op != Py_NE) || !PyWeakref_Check(self) || !PyWeakref_Check(other)) { Py_RETURN_NOTIMPLEMENTED; } - PyObject* obj = PyWeakref_GET_OBJECT(self); - PyObject* other_obj = PyWeakref_GET_OBJECT(other); - if (obj == Py_None || other_obj == Py_None) { + PyObject* obj = _PyWeakref_GET_REF(self); + PyObject* other_obj = _PyWeakref_GET_REF(other); + if (obj == NULL || other_obj == NULL) { + Py_XDECREF(obj); + Py_XDECREF(other_obj); int res = (self == other); if (op == Py_NE) res = !res; @@ -209,8 +209,6 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) else Py_RETURN_FALSE; } - Py_INCREF(obj); - Py_INCREF(other_obj); PyObject* res = PyObject_RichCompare(obj, other_obj, op); Py_DECREF(obj); Py_DECREF(other_obj); @@ -372,7 +370,7 @@ _PyWeakref_RefType = { Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE, .tp_traverse = (traverseproc)gc_traverse, .tp_clear = (inquiry)gc_clear, - .tp_richcompare = (richcmpfunc)weakref_richcompare, + .tp_richcompare = weakref_richcompare, .tp_methods = weakref_methods, .tp_members = weakref_members, .tp_init = weakref___init__, @@ -385,7 +383,7 @@ _PyWeakref_RefType = { static bool proxy_check_ref(PyObject *obj) { - if (obj == Py_None) { + if (obj == NULL) { PyErr_SetString(PyExc_ReferenceError, "weakly-referenced object no longer exists"); return false; @@ -400,16 +398,19 @@ proxy_check_ref(PyObject *obj) */ #define UNWRAP(o) \ if (PyWeakref_CheckProxy(o)) { \ - o = PyWeakref_GET_OBJECT(o); \ - if (!proxy_check_ref(o)) \ + o = _PyWeakref_GET_REF(o); \ + if (!proxy_check_ref(o)) { \ return NULL; \ + } \ + } \ + else { \ + Py_INCREF(o); \ } #define WRAP_UNARY(method, generic) \ static PyObject * \ method(PyObject *proxy) { \ UNWRAP(proxy); \ - Py_INCREF(proxy); \ PyObject* res = generic(proxy); \ Py_DECREF(proxy); \ return res; \ @@ -420,8 +421,6 @@ proxy_check_ref(PyObject *obj) method(PyObject *x, PyObject *y) { \ UNWRAP(x); \ UNWRAP(y); \ - Py_INCREF(x); \ - Py_INCREF(y); \ PyObject* res = generic(x, y); \ Py_DECREF(x); \ Py_DECREF(y); \ @@ -436,11 +435,9 @@ proxy_check_ref(PyObject *obj) method(PyObject *proxy, PyObject *v, PyObject *w) { \ UNWRAP(proxy); \ UNWRAP(v); \ - if (w != NULL) \ + if (w != NULL) { \ UNWRAP(w); \ - Py_INCREF(proxy); \ - Py_INCREF(v); \ - Py_XINCREF(w); \ + } \ PyObject* res = generic(proxy, v, w); \ Py_DECREF(proxy); \ Py_DECREF(v); \ @@ -452,7 +449,6 @@ proxy_check_ref(PyObject *obj) static PyObject * \ method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \ UNWRAP(proxy); \ - Py_INCREF(proxy); \ PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \ Py_DECREF(proxy); \ return res; \ @@ -466,24 +462,24 @@ WRAP_UNARY(proxy_str, PyObject_Str) WRAP_TERNARY(proxy_call, PyObject_Call) static PyObject * -proxy_repr(PyWeakReference *proxy) +proxy_repr(PyObject *proxy) { - return PyUnicode_FromFormat( + PyObject *obj = _PyWeakref_GET_REF(proxy); + PyObject *repr = PyUnicode_FromFormat( "", - proxy, - Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name, - PyWeakref_GET_OBJECT(proxy)); + proxy, Py_TYPE(obj)->tp_name, obj); + Py_DECREF(obj); + return repr; } static int proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return -1; } - Py_INCREF(obj); int res = PyObject_SetAttr(obj, name, value); Py_DECREF(obj); return res; @@ -494,7 +490,10 @@ proxy_richcompare(PyObject *proxy, PyObject *v, int op) { UNWRAP(proxy); UNWRAP(v); - return PyObject_RichCompare(proxy, v, op); + PyObject* res = PyObject_RichCompare(proxy, v, op); + Py_DECREF(proxy); + Py_DECREF(v); + return res; } /* number slots */ @@ -536,11 +535,10 @@ WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply) static int proxy_bool(PyObject *proxy) { - PyObject *o = PyWeakref_GET_OBJECT(proxy); + PyObject *o = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(o)) { return -1; } - Py_INCREF(o); int res = PyObject_IsTrue(o); Py_DECREF(o); return res; @@ -561,11 +559,10 @@ proxy_dealloc(PyWeakReference *self) static int proxy_contains(PyObject *proxy, PyObject *value) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return -1; } - Py_INCREF(obj); int res = PySequence_Contains(obj, value); Py_DECREF(obj); return res; @@ -576,11 +573,10 @@ proxy_contains(PyObject *proxy, PyObject *value) static Py_ssize_t proxy_length(PyObject *proxy) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return -1; } - Py_INCREF(obj); Py_ssize_t res = PyObject_Length(obj); Py_DECREF(obj); return res; @@ -591,11 +587,10 @@ WRAP_BINARY(proxy_getitem, PyObject_GetItem) static int proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return -1; } - Py_INCREF(obj); int res; if (value == NULL) { res = PyObject_DelItem(obj, key); @@ -611,11 +606,10 @@ proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value) static PyObject * proxy_iter(PyObject *proxy) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return NULL; } - Py_INCREF(obj); PyObject* res = PyObject_GetIter(obj); Py_DECREF(obj); return res; @@ -624,7 +618,7 @@ proxy_iter(PyObject *proxy) static PyObject * proxy_iternext(PyObject *proxy) { - PyObject *obj = PyWeakref_GET_OBJECT(proxy); + PyObject *obj = _PyWeakref_GET_REF(proxy); if (!proxy_check_ref(obj)) { return NULL; } @@ -632,9 +626,9 @@ proxy_iternext(PyObject *proxy) PyErr_Format(PyExc_TypeError, "Weakref proxy referenced a non-iterator '%.200s' object", Py_TYPE(obj)->tp_name); + Py_DECREF(obj); return NULL; } - Py_INCREF(obj); PyObject* res = PyIter_Next(obj); Py_DECREF(obj); return res; @@ -721,7 +715,7 @@ _PyWeakref_ProxyType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)proxy_repr, /* tp_repr */ + proxy_repr, /* tp_repr */ &proxy_as_number, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ &proxy_as_mapping, /* tp_as_mapping */ @@ -756,7 +750,7 @@ _PyWeakref_CallableProxyType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (unaryfunc)proxy_repr, /* tp_repr */ + proxy_repr, /* tp_repr */ &proxy_as_number, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ &proxy_as_mapping, /* tp_as_mapping */ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 72d869efb9db67..a68452a916aa3c 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -275,6 +275,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 5d8b7196c14e6a..bf9b42f4d790e3 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -492,6 +492,9 @@ Include\internal + + Include\internal + Include\internal From 155577de1b6a7f4404b2bf90bcc1a588201550da Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 10:12:44 +0200 Subject: [PATCH 092/446] make regen-stdlib-module-names rejects test modules (#105921) Make sure that sys.stdlib_module_names doesn't contain test modules. --- Tools/build/generate_stdlib_module_names.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Tools/build/generate_stdlib_module_names.py b/Tools/build/generate_stdlib_module_names.py index 17668f4a456473..72f6923c7c316a 100644 --- a/Tools/build/generate_stdlib_module_names.py +++ b/Tools/build/generate_stdlib_module_names.py @@ -43,6 +43,16 @@ 'xxsubtype', } +ALLOW_TEST_MODULES = { + 'doctest', + 'unittest', +} + +# Built-in modules +def list_builtin_modules(names): + names |= set(sys.builtin_module_names) + + # Pure Python modules (Lib/*.py) def list_python_modules(names): for filename in os.listdir(STDLIB_PATH): @@ -93,7 +103,9 @@ def list_frozen(names): def list_modules(): - names = set(sys.builtin_module_names) + names = set() + + list_builtin_modules(names) list_modules_setup_extensions(names) list_packages(names) list_python_modules(names) @@ -106,9 +118,12 @@ def list_modules(): if package_name in IGNORE: names.discard(name) + # Sanity checks for name in names: if "." in name: - raise Exception("sub-modules must not be listed") + raise Exception(f"sub-modules must not be listed: {name}") + if ("test" in name or "xx" in name) and name not in ALLOW_TEST_MODULES: + raise Exception(f"test modules must not be listed: {name}") return names From 6586cee27f32f0354fe4e77c7b8c6e399329b5e2 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 20 Jun 2023 14:38:46 +0200 Subject: [PATCH 093/446] gh-105938: Emit a SyntaxWarning for escaped braces in an f-string (#105939) --- Lib/test/test_fstring.py | 11 +++++++++-- Parser/string_parser.c | 7 ++++++- Parser/tokenizer.c | 6 +++--- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 8f6b576b5f785f..ad5ac6a2f0432e 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -13,6 +13,7 @@ import types import decimal import unittest +import warnings from test import support from test.support.os_helper import temp_cwd from test.support.script_helper import assert_python_failure, assert_python_ok @@ -904,7 +905,7 @@ def test_backslashes_in_string_part(self): self.assertEqual(f'2\x203', '2 3') self.assertEqual(f'\x203', ' 3') - with self.assertWarns(DeprecationWarning): # invalid escape sequence + with self.assertWarns(SyntaxWarning): # invalid escape sequence value = eval(r"f'\{6*7}'") self.assertEqual(value, '\\42') with self.assertWarns(SyntaxWarning): # invalid escape sequence @@ -1037,7 +1038,7 @@ def test_fstring_backslash_before_double_bracket(self): ] for case, expected_result in deprecated_cases: with self.subTest(case=case, expected_result=expected_result): - with self.assertWarns(DeprecationWarning): + with self.assertWarns(SyntaxWarning): result = eval(case) self.assertEqual(result, expected_result) self.assertEqual(fr'\{{\}}', '\\{\\}') @@ -1046,6 +1047,12 @@ def test_fstring_backslash_before_double_bracket(self): self.assertEqual(fr'\}}{1+1}', '\\}2') self.assertEqual(fr'{1+1}\}}', '2\\}') + def test_fstring_backslash_before_double_bracket_warns_once(self): + with warnings.catch_warnings(record=True) as w: + eval(r"f'\{{'") + self.assertEqual(len(w), 1) + self.assertEqual(w[0].category, SyntaxWarning) + def test_fstring_backslash_prefix_raw(self): self.assertEqual(f'\\', '\\') self.assertEqual(f'\\\\', '\\\\') diff --git a/Parser/string_parser.c b/Parser/string_parser.c index d4ce33850f7c58..20459e89463494 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -12,6 +12,11 @@ static int warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t) { unsigned char c = *first_invalid_escape; + if ((t->type == FSTRING_MIDDLE || t->type == FSTRING_END) && (c == '{' || c == '}')) { // in this case the tokenizer has already emitted a warning, + // see tokenizer.c:warn_invalid_escape_sequence + return 0; + } + int octal = ('4' <= c && c <= '7'); PyObject *msg = octal @@ -31,7 +36,7 @@ warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token if (PyErr_WarnExplicitObject(category, msg, p->tok->filename, t->lineno, NULL, NULL) < 0) { if (PyErr_ExceptionMatches(category)) { - /* Replace the DeprecationWarning exception with a SyntaxError + /* Replace the Syntax/DeprecationWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 4f7b1f8114e96f..6bdf371a7adf03 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1559,12 +1559,12 @@ warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_cha return -1; } - if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename, + if (PyErr_WarnExplicitObject(PyExc_SyntaxWarning, msg, tok->filename, tok->lineno, NULL, NULL) < 0) { Py_DECREF(msg); - if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) { - /* Replace the DeprecationWarning exception with a SyntaxError + if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { + /* Replace the SyntaxWarning exception with a SyntaxError to get a more accurate error report */ PyErr_Clear(); return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char); From 4b431d2e90bf5760a57aa40af2dd78e7bbf0b1ae Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 20 Jun 2023 14:49:00 +0200 Subject: [PATCH 094/446] gh-105915: Add 'r' prefix to not emit SyntaxWarning in test_fstring (#105940) Co-authored-by: @sunmy2019 --- Lib/test/test_fstring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index ad5ac6a2f0432e..1eb3bfb41888c2 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -773,7 +773,7 @@ def __format__(self, format_spec): self.assertEqual(f'{CustomFormat():\n}', '\n') self.assertEqual(f'{CustomFormat():\u2603}', '☃') with self.assertWarns(SyntaxWarning): - exec('f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) + exec(r'f"{F():¯\_(ツ)_/¯}"', {'F': CustomFormat}) def test_side_effect_order(self): class X: From 6e40ee6e8456da04d6970a46863300c043c81208 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 20 Jun 2023 16:13:07 +0200 Subject: [PATCH 095/446] gh-105915: Fix SyntaxWarning becoming a SyntaxError with -We in test_fstring (#105943) --- Lib/test/test_fstring.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 1eb3bfb41888c2..ba223ae124a8fb 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1048,10 +1048,10 @@ def test_fstring_backslash_before_double_bracket(self): self.assertEqual(fr'{1+1}\}}', '2\\}') def test_fstring_backslash_before_double_bracket_warns_once(self): - with warnings.catch_warnings(record=True) as w: + with self.assertWarns(SyntaxWarning) as w: eval(r"f'\{{'") - self.assertEqual(len(w), 1) - self.assertEqual(w[0].category, SyntaxWarning) + self.assertEqual(len(w.warnings), 1) + self.assertEqual(w.warnings[0].category, SyntaxWarning) def test_fstring_backslash_prefix_raw(self): self.assertEqual(f'\\', '\\') From 4d140e5e067d3315e163c0f1ac2f80c05ec790c6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 20 Jun 2023 23:57:54 +0200 Subject: [PATCH 096/446] Add Py_TYPE() to Doc/data/refcounts.dat (#105949) --- Doc/data/refcounts.dat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index d707cc34c98c97..d6ab0b28e65874 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1797,6 +1797,9 @@ PyObject_Size:PyObject*:o:0: PyObject_Str:PyObject*::+1: PyObject_Str:PyObject*:o:0: +Py_TYPE:PyObject*::0: +Py_TYPE:PyObject*:ob:0: + PyObject_Type:PyObject*::+1: PyObject_Type:PyObject*:o:0: From 9c44656febdcf72583e192ea4530fcfb0936c309 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 11:40:09 +0200 Subject: [PATCH 097/446] gh-105927: Add PyWeakref_GetRef() function (#105932) Add tests on PyWeakref_NewRef(), PyWeakref_GetObject(), PyWeakref_GET_OBJECT() and PyWeakref_GetRef(). --- Doc/c-api/weakref.rst | 27 +++++-- Doc/data/refcounts.dat | 4 + Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.13.rst | 4 + Include/weakrefobject.h | 1 + Lib/test/test_stable_abi_ctypes.py | 1 + ...-06-20-08-59-05.gh-issue-105927.DfGeEA.rst | 3 + Misc/stable_abi.toml | 2 + Modules/_testcapimodule.c | 79 +++++++++++++++++++ Objects/weakrefobject.c | 18 +++++ PC/python3dll.c | 1 + 11 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-20-08-59-05.gh-issue-105927.DfGeEA.rst diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index f27ec4411b4a26..44f4dce9ea0238 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -11,20 +11,20 @@ simple reference object, and the second acts as a proxy for the original object as much as it can. -.. c:function:: int PyWeakref_Check(ob) +.. c:function:: int PyWeakref_Check(PyObject *ob) - Return true if *ob* is either a reference or proxy object. This function + Return non-zero if *ob* is either a reference or proxy object. This function always succeeds. -.. c:function:: int PyWeakref_CheckRef(ob) +.. c:function:: int PyWeakref_CheckRef(PyObject *ob) - Return true if *ob* is a reference object. This function always succeeds. + Return non-zero if *ob* is a reference object. This function always succeeds. -.. c:function:: int PyWeakref_CheckProxy(ob) +.. c:function:: int PyWeakref_CheckProxy(PyObject *ob) - Return true if *ob* is a proxy object. This function always succeeds. + Return non-zero if *ob* is a proxy object. This function always succeeds. .. c:function:: PyObject* PyWeakref_NewRef(PyObject *ob, PyObject *callback) @@ -51,10 +51,21 @@ as much as it can. ``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`. +.. c:function:: int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) + + Get a :term:`strong reference` to the referenced object from a weak + reference, *ref*, into *\*pobj*. + Return 0 on success. Raise an exception and return -1 on error. + + If the referent is no longer live, set *\*pobj* to ``NULL`` and return 0. + + .. versionadded:: 3.13 + + .. c:function:: PyObject* PyWeakref_GetObject(PyObject *ref) - Return the referenced object from a weak reference, *ref*. If the referent is - no longer live, returns :const:`Py_None`. + Return a :term:`borrowed reference` to the referenced object from a weak + reference, *ref*. If the referent is no longer live, returns ``Py_None``. .. note:: diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index d6ab0b28e65874..ef9ac1617a284b 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -2813,6 +2813,10 @@ PyWeakref_GET_OBJECT:PyObject*:ref:0: PyWeakref_GetObject:PyObject*::0: PyWeakref_GetObject:PyObject*:ref:0: +PyWeakref_GetRef:int::: +PyWeakref_GetRef:PyObject*:ref:0: +PyWeakref_GetRef:PyObject**:pobj:+1: + PyWeakref_NewProxy:PyObject*::+1: PyWeakref_NewProxy:PyObject*:ob:0: PyWeakref_NewProxy:PyObject*:callback:0: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index a3fde01cf67f3c..7fb002cd80369b 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -781,6 +781,7 @@ function,PyVectorcall_Call,3.12,, function,PyVectorcall_NARGS,3.12,, type,PyWeakReference,3.2,,opaque function,PyWeakref_GetObject,3.2,, +function,PyWeakref_GetRef,3.13,, function,PyWeakref_NewProxy,3.2,, function,PyWeakref_NewRef,3.2,, var,PyWrapperDescr_Type,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index bbe02a9e85b42c..6cf2bd2426370c 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -431,6 +431,10 @@ New Features of a :term:`borrowed reference`. (Contributed by Victor Stinner in :gh:`105922`.) +* Add :c:func:`PyWeakref_GetRef` function: similar to + :c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or + ``NULL`` if the referent is no longer live. + (Contributed by Victor Stinner in :gh:`105927`.) Porting to Python 3.13 ---------------------- diff --git a/Include/weakrefobject.h b/Include/weakrefobject.h index 8e1fa1b9286a77..2c69f9e4564ab3 100644 --- a/Include/weakrefobject.h +++ b/Include/weakrefobject.h @@ -28,6 +28,7 @@ PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, PyObject *callback); PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); +PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj); #ifndef Py_LIMITED_API diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index c26dff5aaf370b..038c978e7bbd02 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -794,6 +794,7 @@ def test_windows_feature_macros(self): "PyVectorcall_Call", "PyVectorcall_NARGS", "PyWeakref_GetObject", + "PyWeakref_GetRef", "PyWeakref_NewProxy", "PyWeakref_NewRef", "PyWrapperDescr_Type", diff --git a/Misc/NEWS.d/next/C API/2023-06-20-08-59-05.gh-issue-105927.DfGeEA.rst b/Misc/NEWS.d/next/C API/2023-06-20-08-59-05.gh-issue-105927.DfGeEA.rst new file mode 100644 index 00000000000000..afa40c8ef5d686 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-20-08-59-05.gh-issue-105927.DfGeEA.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyWeakref_GetRef` function: similar to +:c:func:`PyWeakref_GetObject` but returns a :term:`strong reference`, or +``NULL`` if the referent is no longer live. Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 7025ed4e66b698..bc7259f11816f3 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2430,3 +2430,5 @@ added = '3.12' [function.PyImport_AddModuleRef] added = '3.13' +[function.PyWeakref_GetRef] + added = '3.13' diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 9d4517c8f68b09..8b63f9c90a385d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3372,6 +3372,84 @@ check_pyimport_addmodule(PyObject *self, PyObject *args) } +static PyObject * +test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + // Create a new heap type, create an instance of this type, and delete the + // type. This object supports weak references. + PyObject *new_type = PyObject_CallFunction((PyObject*)&PyType_Type, + "s(){}", "TypeName"); + if (new_type == NULL) { + return NULL; + } + PyObject *obj = PyObject_CallNoArgs(new_type); + Py_DECREF(new_type); + if (obj == NULL) { + return NULL; + } + Py_ssize_t refcnt = Py_REFCNT(obj); + + // test PyWeakref_NewRef(), reference is alive + PyObject *weakref = PyWeakref_NewRef(obj, NULL); + if (weakref == NULL) { + Py_DECREF(obj); + return NULL; + } + assert(PyWeakref_Check(weakref)); + assert(PyWeakref_CheckRefExact(weakref)); + assert(PyWeakref_CheckRefExact(weakref)); + assert(Py_REFCNT(obj) == refcnt); + + // test PyWeakref_GetRef(), reference is alive + PyObject *ref1; + assert(PyWeakref_GetRef(weakref, &ref1) == 0); + assert(ref1 == obj); + assert(Py_REFCNT(obj) == (refcnt + 1)); + Py_DECREF(ref1); + + // test PyWeakref_GetObject(), reference is alive + PyObject *ref2 = PyWeakref_GetObject(weakref); + assert(ref2 == obj); + + // test PyWeakref_GET_OBJECT(), reference is alive + PyObject *ref3 = PyWeakref_GET_OBJECT(weakref); + assert(ref3 == obj); + + // delete the referenced object + assert(Py_REFCNT(obj) == 1); + Py_DECREF(obj); + + // test PyWeakref_GET_OBJECT(), reference is dead + assert(PyWeakref_GET_OBJECT(weakref) == Py_None); + + // test PyWeakref_GetRef(), reference is dead + PyObject *ref4 = Py_True; // marker to check that value was set + assert(PyWeakref_GetRef(weakref, &ref4) == 0); + assert(ref4 == NULL); + + // None is not a weak reference object + PyObject *invalid_weakref = Py_None; + assert(!PyWeakref_Check(invalid_weakref)); + assert(!PyWeakref_CheckRefExact(invalid_weakref)); + assert(!PyWeakref_CheckRefExact(invalid_weakref)); + + // test PyWeakref_GetRef(), invalid type + assert(!PyErr_Occurred()); + PyObject *ref5 = Py_True; // marker to check that value was set + assert(PyWeakref_GetRef(invalid_weakref, &ref5) == -1); + assert(PyErr_ExceptionMatches(PyExc_TypeError)); + PyErr_Clear(); + assert(ref5 == NULL); + + // test PyWeakref_GetObject(), invalid type + assert(PyWeakref_GetObject(invalid_weakref) == NULL); + assert(PyErr_ExceptionMatches(PyExc_SystemError)); + PyErr_Clear(); + + Py_RETURN_NONE; +} + + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3516,6 +3594,7 @@ static PyMethodDef TestMethods[] = { {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, {"test_atexit", test_atexit, METH_NOARGS}, {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, + {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 9995a7756570ca..49342d0658de6b 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -894,6 +894,24 @@ PyWeakref_NewProxy(PyObject *ob, PyObject *callback) } +int +PyWeakref_GetRef(PyObject *ref, PyObject **pobj) +{ + if (ref == NULL) { + *pobj = NULL; + PyErr_BadInternalCall(); + return -1; + } + if (!PyWeakref_Check(ref)) { + *pobj = NULL; + PyErr_SetString(PyExc_TypeError, "expected a weakref"); + return -1; + } + *pobj = _PyWeakref_GET_REF(ref); + return 0; +} + + PyObject * PyWeakref_GetObject(PyObject *ref) { diff --git a/PC/python3dll.c b/PC/python3dll.c index fea19b77185dd5..65bdf326ffbc7f 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -735,6 +735,7 @@ EXPORT_FUNC(PyUnicodeTranslateError_SetStart) EXPORT_FUNC(PyVectorcall_Call) EXPORT_FUNC(PyVectorcall_NARGS) EXPORT_FUNC(PyWeakref_GetObject) +EXPORT_FUNC(PyWeakref_GetRef) EXPORT_FUNC(PyWeakref_NewProxy) EXPORT_FUNC(PyWeakref_NewRef) EXPORT_FUNC(PyWrapper_New) From eaa670228066220f08c8d73f80365c50058d40b8 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 21 Jun 2023 12:42:59 +0200 Subject: [PATCH 098/446] Use CSV-separated outputs @ get-changed-files @ CI (#105151) Co-authored-by: Hugo van Kemenade --- .github/workflows/build.yml | 16 ++------------ .github/workflows/reusable-docs.yml | 4 +++- Doc/tools/touch-clean-files.py | 33 +++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4760c07a6d9cbb..34fcce445d0cd4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,21 +87,9 @@ jobs: with: filter: | Doc/** - # Temporarily skip paths with spaces - # (i.e. "C API", "Core and Builtins") - # to avoid "Error: One of your files includes a space". - # Pending https://github.com/python/core-workflow/issues/186 - # Misc/** - Misc/NEWS.d/next/Build/** - Misc/NEWS.d/next/Documentation/** - Misc/NEWS.d/next/IDLE/** - Misc/NEWS.d/next/Library/** - Misc/NEWS.d/next/Security/** - Misc/NEWS.d/next/Tests/** - Misc/NEWS.d/next/Tools-Demos/** - Misc/NEWS.d/next/Windows/** - Misc/NEWS.d/next/macOS/** + Misc/** .github/workflows/reusable-docs.yml + format: csv # works for paths with spaces - name: Check for docs changes if: >- github.event_name == 'pull_request' diff --git a/.github/workflows/reusable-docs.yml b/.github/workflows/reusable-docs.yml index c5a15a10866e27..b39d8cea6421ea 100644 --- a/.github/workflows/reusable-docs.yml +++ b/.github/workflows/reusable-docs.yml @@ -38,12 +38,14 @@ jobs: uses: Ana06/get-changed-files@v2.2.0 with: filter: "Doc/**" + format: csv # works for paths with spaces - name: 'Build changed files in nit-picky mode' if: github.event_name == 'pull_request' continue-on-error: true run: | + set -Eeuo pipefail # Mark files the pull request modified - touch ${{ steps.changed_files.outputs.added_modified }} + python Doc/tools/touch-clean-files.py --clean '${{ steps.changed_files.outputs.added_modified }}' # Build docs with the '-n' (nit-picky) option; convert warnings to annotations make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n --keep-going" html 2>&1 | python Doc/tools/warnings-to-gh-actions.py diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py index 19bc1be31deb26..2b045bd68a0cf0 100644 --- a/Doc/tools/touch-clean-files.py +++ b/Doc/tools/touch-clean-files.py @@ -3,7 +3,9 @@ Touch files that must pass Sphinx nit-picky mode so they are rebuilt and we can catch regressions. """ - +import argparse +import csv +import sys from pathlib import Path wrong_directory_msg = "Must run this script from the repo root" @@ -28,14 +30,33 @@ rst for rst in Path("Doc/").rglob("*.rst") if rst.parts[1] not in EXCLUDE_SUBDIRS } -with Path("Doc/tools/.nitignore").open() as clean_files: - DIRTY = { + +parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument("-c", "--clean", help="Comma-separated list of clean files") +args = parser.parse_args() + +if args.clean: + clean_files = next(csv.reader([args.clean])) + CLEAN = { Path(filename.strip()) for filename in clean_files - if filename.strip() and not filename.startswith("#") + if Path(filename.strip()).is_file() } - -CLEAN = ALL_RST - DIRTY - EXCLUDE_FILES +elif args.clean is not None: + print( + "Not touching any files: an empty string `--clean` arg value passed.", + ) + sys.exit(0) +else: + with Path("Doc/tools/.nitignore").open() as ignored_files: + IGNORED = { + Path(filename.strip()) + for filename in ignored_files + if filename.strip() and not filename.startswith("#") + } + CLEAN = ALL_RST - IGNORED - EXCLUDE_FILES print("Touching:") for filename in sorted(CLEAN): From fb1e691e4bc7757c11bf9e51dda675f15537db8c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 15:44:25 +0200 Subject: [PATCH 099/446] gh-105927: _abc and _thread use PyWeakref_GetRef() (#105961) Hold a strong reference on the object, rather than using a borrowed reference: replace PyWeakref_GET_OBJECT() with PyWeakref_GetRef() and _PyWeakref_GET_REF(). Remove assert(PyWeakref_CheckRef(localweakref)) since it's already tested by _PyWeakref_GET_REF(). --- Modules/_abc.c | 15 +++++++-------- Modules/_threadmodule.c | 26 +++++++++++++------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/Modules/_abc.c b/Modules/_abc.c index d3e405dadb664a..93c0a93c442cdb 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -8,6 +8,7 @@ #include "pycore_object.h" // _PyType_GetSubclasses() #include "pycore_runtime.h" // _Py_ID() #include "pycore_typeobject.h" // _PyType_GetMRO() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "clinic/_abc.c.h" /*[clinic input] @@ -150,12 +151,10 @@ _in_weak_set(PyObject *set, PyObject *obj) static PyObject * _destroy(PyObject *setweakref, PyObject *objweakref) { - PyObject *set; - set = PyWeakref_GET_OBJECT(setweakref); - if (set == Py_None) { + PyObject *set = _PyWeakref_GET_REF(setweakref); + if (set == NULL) { Py_RETURN_NONE; } - Py_INCREF(set); if (PySet_Discard(set, objweakref) < 0) { Py_DECREF(set); return NULL; @@ -843,16 +842,16 @@ subclasscheck_check_registry(_abc_data *impl, PyObject *subclass, assert(i == registry_size); for (i = 0; i < registry_size; i++) { - PyObject *rkey = PyWeakref_GetObject(copy[i]); - if (rkey == NULL) { + PyObject *rkey; + if (PyWeakref_GetRef(copy[i], &rkey) < 0) { // Someone inject non-weakref type in the registry. ret = -1; break; } - if (rkey == Py_None) { + + if (rkey == NULL) { continue; } - Py_INCREF(rkey); int r = PyObject_IsSubclass(subclass, rkey); Py_DECREF(rkey); if (r < 0) { diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index c553d039462af0..7f8b3cbbfcec7b 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -7,6 +7,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pylifecycle.h" #include "pycore_pystate.h" // _PyThreadState_SetCurrent() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include // offsetof() #include "structmember.h" // PyMemberDef @@ -1024,15 +1025,13 @@ local_getattro(localobject *self, PyObject *name) static PyObject * _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) { - assert(PyWeakref_CheckRef(localweakref)); - PyObject *obj = PyWeakref_GET_OBJECT(localweakref); - if (obj == Py_None) { + localobject *self = (localobject *)_PyWeakref_GET_REF(localweakref); + if (self == NULL) { Py_RETURN_NONE; } /* If the thread-local object is still alive and not being cleared, remove the corresponding local dict */ - localobject *self = (localobject *)Py_NewRef(obj); if (self->dummies != NULL) { PyObject *ldict; ldict = PyDict_GetItemWithError(self->dummies, dummyweakref); @@ -1040,9 +1039,9 @@ _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) PyDict_DelItem(self->dummies, dummyweakref); } if (PyErr_Occurred()) - PyErr_WriteUnraisable(obj); + PyErr_WriteUnraisable((PyObject*)self); } - Py_DECREF(obj); + Py_DECREF(self); Py_RETURN_NONE; } @@ -1314,24 +1313,25 @@ This function is meant for internal and specialized purposes only.\n\ In most applications `threading.enumerate()` should be used instead."); static void -release_sentinel(void *wr_raw) +release_sentinel(void *weakref_raw) { - PyObject *wr = _PyObject_CAST(wr_raw); + PyObject *weakref = _PyObject_CAST(weakref_raw); + /* Tricky: this function is called when the current thread state is being deleted. Therefore, only simple C code can safely execute here. */ - PyObject *obj = PyWeakref_GET_OBJECT(wr); - lockobject *lock; - if (obj != Py_None) { - lock = (lockobject *) obj; + lockobject *lock = (lockobject *)_PyWeakref_GET_REF(weakref); + if (lock != NULL) { if (lock->locked) { PyThread_release_lock(lock->lock_lock); lock->locked = 0; } + Py_DECREF(lock); } + /* Deallocating a weakref with a NULL callback only calls PyObject_GC_Del(), which can't call any Python code. */ - Py_DECREF(wr); + Py_DECREF(weakref); } static PyObject * From c5a722be5f7979c73e2451e537a8fc58bf9af12e Mon Sep 17 00:00:00 2001 From: Mathieu Dupuy Date: Wed, 21 Jun 2023 16:21:37 +0200 Subject: [PATCH 100/446] stdtypes.rst: remove a period (#105959) --- Doc/library/stdtypes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 0caa725f75e642..0ac727e0df38b3 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -52,7 +52,7 @@ objects considered false: single: None (Built-in object) single: False (Built-in object) -* constants defined to be false: ``None`` and ``False``. +* constants defined to be false: ``None`` and ``False`` * zero of any numeric type: ``0``, ``0.0``, ``0j``, ``Decimal(0)``, ``Fraction(0, 1)`` From 74da6f7c9f7ace6ff5ee9a8e5abd10e28ebe90ae Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 16:33:32 +0200 Subject: [PATCH 101/446] gh-105927: _ssl uses _PyWeakref_GET_REF() (#105965) --- Modules/_ssl.c | 37 ++++++++++++++++++++++++------------- Modules/_ssl/debughelpers.c | 10 +++++----- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 7a13821f9d7b5c..9ce61a651c2cbb 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -14,6 +14,10 @@ http://bugs.python.org/issue8108#msg102867 ? */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + /* Don't warn about deprecated functions, */ #ifndef OPENSSL_API_COMPAT // 0x10101000L == 1.1.1, 30000 == 3.0.0 @@ -24,6 +28,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_weakref.h" // _PyWeakref_GET_REF() /* Include symbols from _socket module */ #include "socketmodule.h" @@ -379,8 +384,14 @@ typedef enum { #define ERRSTR(x) ERRSTR1("_ssl.c", Py_STRINGIFY(__LINE__), x) /* Get the socket from a PySSLSocket, if it has one */ -#define GET_SOCKET(obj) ((obj)->Socket ? \ - (PySocketSockObject *) PyWeakref_GetObject((obj)->Socket) : NULL) +static inline PySocketSockObject* GET_SOCKET(PySSLSocket *obj) { + if (obj->Socket) { + return (PySocketSockObject *)PyWeakref_GetObject(obj->Socket); + } + else { + return NULL; + } +} /* If sock is NULL, use a timeout of 0 second */ #define GET_SOCKET_TIMEOUT(sock) \ @@ -2177,13 +2188,14 @@ PyDoc_STRVAR(PySSL_get_server_hostname_doc, static PyObject * PySSL_get_owner(PySSLSocket *self, void *c) { - PyObject *owner; - - if (self->owner == NULL) + if (self->owner == NULL) { Py_RETURN_NONE; - - owner = PyWeakref_GetObject(self->owner); - return Py_NewRef(owner); + } + PyObject *owner = _PyWeakref_GET_REF(self->owner); + if (owner == NULL) { + Py_RETURN_NONE; + } + return owner; } static int @@ -4393,14 +4405,13 @@ _servername_callback(SSL *s, int *al, void *args) * will be passed. If both do not exist only then the C-level object is * passed. */ if (ssl->owner) - ssl_socket = PyWeakref_GetObject(ssl->owner); + ssl_socket = _PyWeakref_GET_REF(ssl->owner); else if (ssl->Socket) - ssl_socket = PyWeakref_GetObject(ssl->Socket); + ssl_socket = _PyWeakref_GET_REF(ssl->Socket); else - ssl_socket = (PyObject *) ssl; + ssl_socket = Py_NewRef(ssl); - Py_INCREF(ssl_socket); - if (ssl_socket == Py_None) + if (ssl_socket == NULL) goto error; if (servername == NULL) { diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index a81f0aad05a802..07e9ce7a6fce2d 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -15,7 +15,6 @@ _PySSL_msg_callback(int write_p, int version, int content_type, PyGILState_STATE threadstate; PyObject *res = NULL; PySSLSocket *ssl_obj = NULL; /* ssl._SSLSocket, borrowed ref */ - PyObject *ssl_socket = NULL; /* ssl.SSLSocket or ssl.SSLObject */ int msg_type; threadstate = PyGILState_Ensure(); @@ -27,13 +26,14 @@ _PySSL_msg_callback(int write_p, int version, int content_type, return; } + PyObject *ssl_socket; /* ssl.SSLSocket or ssl.SSLObject */ if (ssl_obj->owner) - ssl_socket = PyWeakref_GetObject(ssl_obj->owner); + ssl_socket = _PyWeakref_GET_REF(ssl_obj->owner); else if (ssl_obj->Socket) - ssl_socket = PyWeakref_GetObject(ssl_obj->Socket); + ssl_socket = _PyWeakref_GET_REF(ssl_obj->Socket); else - ssl_socket = (PyObject *)ssl_obj; - Py_INCREF(ssl_socket); + ssl_socket = (PyObject *)Py_NewRef(ssl_obj); + assert(ssl_socket != NULL); // _PyWeakref_GET_REF() can return NULL /* assume that OpenSSL verifies all payload and buf len is of sufficient length */ From 48d107a87d74b0e6662b0096454279a6066f7da4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 16:34:27 +0200 Subject: [PATCH 102/446] gh-105927: _ctypes use PyWeakref_GetRef() (#105964) Rename PyDict_GetItemProxy() to _PyDict_GetItemProxy() and mark it as static. _PyDict_GetItemProxy() now returns a strong reference, instead of a borrowed reference: replace PyWeakref_GET_OBJECT() with _PyWeakref_GET_REF(). --- Modules/_ctypes/_ctypes.c | 44 +++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 534ef8c1d6cf8f..840d0df85e9c87 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -238,20 +238,29 @@ PyDict_SetItemProxy(PyObject *dict, PyObject *key, PyObject *item) return result; } -PyObject * -PyDict_GetItemProxy(PyObject *dict, PyObject *key) +static int +_PyDict_GetItemProxy(PyObject *dict, PyObject *key, PyObject **presult) { - PyObject *result; PyObject *item = PyDict_GetItemWithError(dict, key); + if (item == NULL) { + if (PyErr_Occurred()) { + return -1; + } + *presult = NULL; + return 0; + } - if (item == NULL) - return NULL; - if (!PyWeakref_CheckProxy(item)) - return item; - result = PyWeakref_GET_OBJECT(item); - if (result == Py_None) - return NULL; - return result; + if (!PyWeakref_CheckProxy(item)) { + *presult = Py_NewRef(item); + return 0; + } + PyObject *ref; + if (PyWeakref_GetRef(item, &ref) < 0) { + return -1; + } + // ref is NULL if the referenced object was destroyed + *presult = ref; + return 0; } /******************************************************************/ @@ -4832,7 +4841,6 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length) { static PyObject *cache; PyObject *key; - PyObject *result; char name[256]; PyObject *len; @@ -4848,15 +4856,15 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length) Py_DECREF(len); if (!key) return NULL; - result = PyDict_GetItemProxy(cache, key); - if (result) { - Py_INCREF(result); + + PyObject *result; + if (_PyDict_GetItemProxy(cache, key, &result) < 0) { Py_DECREF(key); - return result; + return NULL; } - else if (PyErr_Occurred()) { + if (result) { Py_DECREF(key); - return NULL; + return result; } if (!PyType_Check(itemtype)) { From 2178bbc12195104e94995ec075ad5f7c69d1ec78 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 16:35:41 +0200 Subject: [PATCH 103/446] gh-105927: Fix test_weakref_capi() refleak (#105966) Test PyWeakref_GetRef(NULL) and PyWeakref_GetObject(NULL). --- Modules/_testcapimodule.c | 48 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 8b63f9c90a385d..d847539f6608dd 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3395,27 +3395,29 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_DECREF(obj); return NULL; } + + // test PyWeakref_Check(), valid weakref object assert(PyWeakref_Check(weakref)); assert(PyWeakref_CheckRefExact(weakref)); assert(PyWeakref_CheckRefExact(weakref)); assert(Py_REFCNT(obj) == refcnt); // test PyWeakref_GetRef(), reference is alive - PyObject *ref1; - assert(PyWeakref_GetRef(weakref, &ref1) == 0); - assert(ref1 == obj); + PyObject *ref = Py_True; // marker to check that value was set + assert(PyWeakref_GetRef(weakref, &ref) == 0); + assert(ref == obj); assert(Py_REFCNT(obj) == (refcnt + 1)); - Py_DECREF(ref1); + Py_DECREF(ref); // test PyWeakref_GetObject(), reference is alive - PyObject *ref2 = PyWeakref_GetObject(weakref); - assert(ref2 == obj); + ref = PyWeakref_GetObject(weakref); // borrowed ref + assert(ref == obj); // test PyWeakref_GET_OBJECT(), reference is alive - PyObject *ref3 = PyWeakref_GET_OBJECT(weakref); - assert(ref3 == obj); + ref = PyWeakref_GET_OBJECT(weakref); // borrowed ref + assert(ref == obj); - // delete the referenced object + // delete the referenced object: clear the weakref assert(Py_REFCNT(obj) == 1); Py_DECREF(obj); @@ -3423,11 +3425,11 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) assert(PyWeakref_GET_OBJECT(weakref) == Py_None); // test PyWeakref_GetRef(), reference is dead - PyObject *ref4 = Py_True; // marker to check that value was set - assert(PyWeakref_GetRef(weakref, &ref4) == 0); - assert(ref4 == NULL); + ref = Py_True; + assert(PyWeakref_GetRef(weakref, &ref) == 0); + assert(ref == NULL); - // None is not a weak reference object + // test PyWeakref_Check(), not a weakref object PyObject *invalid_weakref = Py_None; assert(!PyWeakref_Check(invalid_weakref)); assert(!PyWeakref_CheckRefExact(invalid_weakref)); @@ -3435,17 +3437,31 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) // test PyWeakref_GetRef(), invalid type assert(!PyErr_Occurred()); - PyObject *ref5 = Py_True; // marker to check that value was set - assert(PyWeakref_GetRef(invalid_weakref, &ref5) == -1); + ref = Py_True; + assert(PyWeakref_GetRef(invalid_weakref, &ref) == -1); assert(PyErr_ExceptionMatches(PyExc_TypeError)); PyErr_Clear(); - assert(ref5 == NULL); + assert(ref == NULL); // test PyWeakref_GetObject(), invalid type assert(PyWeakref_GetObject(invalid_weakref) == NULL); assert(PyErr_ExceptionMatches(PyExc_SystemError)); PyErr_Clear(); + // test PyWeakref_GetRef(NULL) + ref = Py_True; // marker to check that value was set + assert(PyWeakref_GetRef(NULL, &ref) == -1); + assert(PyErr_ExceptionMatches(PyExc_SystemError)); + assert(ref == NULL); + PyErr_Clear(); + + // test PyWeakref_GetObject(NULL) + assert(PyWeakref_GetObject(NULL) == NULL); + assert(PyErr_ExceptionMatches(PyExc_SystemError)); + PyErr_Clear(); + + Py_DECREF(weakref); + Py_RETURN_NONE; } From fc32522b081c895f3798e4a16788b800cff08166 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 16:35:58 +0200 Subject: [PATCH 104/446] gh-105927: type_from_ref() uses _PyWeakref_GET_REF() (#105963) type_from_ref() now returns a strong reference to the type, instead of a borrowed reference: replace PyWeakref_GET_OBJECT() with _PyWeakref_GET_REF(). --- Objects/typeobject.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5d29d262575315..cbba6f0fa80d12 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3,18 +3,19 @@ #include "Python.h" #include "pycore_call.h" #include "pycore_code.h" // CO_FAST_FREE -#include "pycore_symtable.h" // _Py_Mangle() #include "pycore_dict.h" // _PyDict_KeysSize() +#include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() -#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_symtable.h" // _Py_Mangle() #include "pycore_typeobject.h" // struct type_cache #include "pycore_unionobject.h" // _Py_union_type_or -#include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "opcode.h" // MAKE_CELL #include "structmember.h" // PyMemberDef @@ -75,13 +76,10 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value); static inline PyTypeObject * type_from_ref(PyObject *ref) { - assert(PyWeakref_CheckRef(ref)); - PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref - assert(obj != NULL); - if (obj == Py_None) { + PyObject *obj = _PyWeakref_GET_REF(ref); + if (obj == NULL) { return NULL; } - assert(PyType_Check(obj)); return _PyType_CAST(obj); } @@ -450,15 +448,17 @@ _PyType_GetSubclasses(PyTypeObject *self) Py_ssize_t i = 0; PyObject *ref; // borrowed ref while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = type_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); if (subclass == NULL) { continue; } if (PyList_Append(list, _PyObject_CAST(subclass)) < 0) { Py_DECREF(list); + Py_DECREF(subclass); return NULL; } + Py_DECREF(subclass); } return list; } @@ -778,11 +778,12 @@ PyType_Modified(PyTypeObject *type) Py_ssize_t i = 0; PyObject *ref; while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = type_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); if (subclass == NULL) { continue; } PyType_Modified(subclass); + Py_DECREF(subclass); } } @@ -4989,12 +4990,13 @@ clear_static_tp_subclasses(PyTypeObject *type) Py_ssize_t i = 0; PyObject *key, *ref; // borrowed ref while (PyDict_Next(subclasses, &i, &key, &ref)) { - PyTypeObject *subclass = type_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); if (subclass == NULL) { continue; } // All static builtin subtypes should have been finalized already. assert(!(subclass->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); + Py_DECREF(subclass); } clear_tp_subclasses(type); @@ -7636,10 +7638,15 @@ get_subclasses_key(PyTypeObject *type, PyTypeObject *base) PyObject *subclasses = lookup_tp_subclasses(base); if (subclasses != NULL) { while (PyDict_Next(subclasses, &i, &key, &ref)) { - PyTypeObject *subclass = type_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); + if (subclass == NULL) { + continue; + } if (subclass == type) { + Py_DECREF(subclass); return Py_NewRef(key); } + Py_DECREF(subclass); } } /* It wasn't found. */ @@ -10035,7 +10042,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, Py_ssize_t i = 0; PyObject *ref; while (PyDict_Next(subclasses, &i, NULL, &ref)) { - PyTypeObject *subclass = type_from_ref(ref); // borrowed + PyTypeObject *subclass = type_from_ref(ref); if (subclass == NULL) { continue; } @@ -10045,16 +10052,20 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *attr_name, if (dict != NULL && PyDict_Check(dict)) { int r = PyDict_Contains(dict, attr_name); if (r < 0) { + Py_DECREF(subclass); return -1; } if (r > 0) { + Py_DECREF(subclass); continue; } } if (update_subclasses(subclass, attr_name, callback, data) < 0) { + Py_DECREF(subclass); return -1; } + Py_DECREF(subclass); } return 0; } From 4328dc646517f9251bdf6c827014f01c5229e8d9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 21 Jun 2023 21:50:20 +0200 Subject: [PATCH 105/446] gh-105927: finalize_modules_clear_weaklist() uses _PyWeakref_GET_REF() (#105971) finalize_modules_clear_weaklist() now holds a strong reference to the module longer than before: replace PyWeakref_GET_OBJECT() with _PyWeakref_GET_REF(). --- Include/internal/pycore_moduleobject.h | 2 +- Objects/moduleobject.c | 2 +- Python/pylifecycle.c | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index 15a1bcb6ae5163..31a31e724d0b21 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -33,7 +33,7 @@ static inline PyObject* _PyModule_GetDict(PyObject *mod) { PyObject *dict = ((PyModuleObject *)mod) -> md_dict; // _PyModule_GetDict(mod) must not be used after calling module_clear(mod) assert(dict != NULL); - return dict; + return dict; // borrowed reference } PyObject* _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress); diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 985be58d02c784..bda25c881845ce 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -504,7 +504,7 @@ PyModule_GetDict(PyObject *m) PyErr_BadInternalCall(); return NULL; } - return _PyModule_GetDict(m); + return _PyModule_GetDict(m); // borrowed reference } PyObject* diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ff9694886b6a45..5a5b14fbb03144 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -28,6 +28,7 @@ #include "pycore_typeobject.h" // _PyTypes_InitTypes() #include "pycore_typevarobject.h" // _Py_clear_generic_types() #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "opcode.h" #include // setlocale() @@ -1464,16 +1465,16 @@ finalize_modules_clear_weaklist(PyInterpreterState *interp, for (Py_ssize_t i = PyList_GET_SIZE(weaklist) - 1; i >= 0; i--) { PyObject *tup = PyList_GET_ITEM(weaklist, i); PyObject *name = PyTuple_GET_ITEM(tup, 0); - PyObject *mod = PyWeakref_GET_OBJECT(PyTuple_GET_ITEM(tup, 1)); - if (mod == Py_None) { + PyObject *mod = _PyWeakref_GET_REF(PyTuple_GET_ITEM(tup, 1)); + if (mod == NULL) { continue; } assert(PyModule_Check(mod)); - PyObject *dict = PyModule_GetDict(mod); + PyObject *dict = _PyModule_GetDict(mod); // borrowed reference if (dict == interp->builtins || dict == interp->sysdict) { + Py_DECREF(mod); continue; } - Py_INCREF(mod); if (verbose && PyUnicode_Check(name)) { PySys_FormatStderr("# cleanup[3] wiping %U\n", name); } From a2392720d6108041d17960a86514ba859b436f05 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:13:25 +0100 Subject: [PATCH 106/446] gh-84436: update docs on Py_None/Py_True/Py_False/Py_Ellipsis becoming immortal (#105195) --- Doc/c-api/bool.rst | 25 ++++++++++++++----------- Doc/c-api/none.rst | 10 +++++----- Doc/c-api/slice.rst | 9 ++++++--- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/Doc/c-api/bool.rst b/Doc/c-api/bool.rst index c197d447e9618c..b2d8f2124fc203 100644 --- a/Doc/c-api/bool.rst +++ b/Doc/c-api/bool.rst @@ -6,7 +6,7 @@ Boolean Objects --------------- Booleans in Python are implemented as a subclass of integers. There are only -two booleans, :const:`Py_False` and :const:`Py_True`. As such, the normal +two booleans, :c:data:`Py_False` and :c:data:`Py_True`. As such, the normal creation and deletion functions don't apply to booleans. The following macros are available, however. @@ -19,29 +19,32 @@ are available, however. .. c:var:: PyObject* Py_False - The Python ``False`` object. This object has no methods. It needs to be - treated just like any other object with respect to reference counts. + The Python ``False`` object. This object has no methods and is + `immortal `_. + +.. versionchanged:: 3.12 + :c:data:`Py_False` is immortal. .. c:var:: PyObject* Py_True - The Python ``True`` object. This object has no methods. It needs to be treated - just like any other object with respect to reference counts. + The Python ``True`` object. This object has no methods and is + `immortal `_. + +.. versionchanged:: 3.12 + :c:data:`Py_True` is immortal. .. c:macro:: Py_RETURN_FALSE - Return :const:`Py_False` from a function, properly incrementing its reference - count. + Return :c:data:`Py_False` from a function. .. c:macro:: Py_RETURN_TRUE - Return :const:`Py_True` from a function, properly incrementing its reference - count. + Return :c:data:`Py_True` from a function. .. c:function:: PyObject* PyBool_FromLong(long v) - Return a new reference to :const:`Py_True` or :const:`Py_False` depending on the - truth value of *v*. + Return :c:data:`Py_True` or :c:data:`Py_False`, depending on the truth value of *v*. diff --git a/Doc/c-api/none.rst b/Doc/c-api/none.rst index b84a16a28ead56..1a497652ac5655 100644 --- a/Doc/c-api/none.rst +++ b/Doc/c-api/none.rst @@ -15,12 +15,12 @@ same reason. .. c:var:: PyObject* Py_None - The Python ``None`` object, denoting lack of value. This object has no methods. - It needs to be treated just like any other object with respect to reference - counts. + The Python ``None`` object, denoting lack of value. This object has no methods + and is `immortal `_. +.. versionchanged:: 3.12 + :c:data:`Py_None` is immortal. .. c:macro:: Py_RETURN_NONE - Properly handle returning :c:data:`Py_None` from within a C function (that is, - increment the reference count of ``None`` and return it.) + Return :c:data:`Py_None` from a function. diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst index 33169ccce89043..c54a659cf2ffd8 100644 --- a/Doc/c-api/slice.rst +++ b/Doc/c-api/slice.rst @@ -118,6 +118,9 @@ Ellipsis Object .. c:var:: PyObject *Py_Ellipsis - The Python ``Ellipsis`` object. This object has no methods. It needs to be - treated just like any other object with respect to reference counts. Like - :c:data:`Py_None` it is a singleton object. + The Python ``Ellipsis`` object. This object has no methods. Like + :c:data:`Py_None`, it is an `immortal `_. + singleton object. + + .. versionchanged:: 3.12 + :c:data:`Py_Ellipsis` is immortal. From 18a7c86697493510993e43bafe8bd4046928bec5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 22 Jun 2023 00:18:31 +0200 Subject: [PATCH 107/446] gh-104212: Explain how to port imp.load_source() (#105978) Explain how to port removed imp.load_source() to importlib in What's New in Python 3.12. --- Doc/whatsnew/3.12.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1a50bce0b65e0b..d8a236080c0056 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1386,6 +1386,21 @@ Removed ``imp.source_from_cache()`` :func:`importlib.util.source_from_cache` ================================= ======================================= + * Replace ``imp.load_source()`` with:: + + import importlib.util + import importlib.machinery + + def load_source(modname, filename): + loader = importlib.machinery.SourceFileLoader(modname, filename) + spec = importlib.util.spec_from_file_location(modname, filename, loader=loader) + module = importlib.util.module_from_spec(spec) + # The module is always executed and not cached in sys.modules. + # Uncomment the following line to cache the module. + # sys.modules[module.__name__] = module + loader.exec_module(module) + return module + * Removed :mod:`!imp` functions and attributes with no replacements: * undocumented functions: @@ -1394,7 +1409,6 @@ Removed * ``imp.load_compiled()`` * ``imp.load_dynamic()`` * ``imp.load_package()`` - * ``imp.load_source()`` * ``imp.lock_held()``, ``imp.acquire_lock()``, ``imp.release_lock()``: the locking scheme has changed in Python 3.3 to per-module locks. From c01da2896ab92ba7193bcd6ae56908c5c7277e75 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 22 Jun 2023 00:14:43 +0100 Subject: [PATCH 108/446] gh-105481: refactor instr flag related code into a new InstructionFlags class (#105950) --- Tools/cases_generator/generate_cases.py | 114 ++++++++++++++++-------- 1 file changed, 78 insertions(+), 36 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index e4ccd38bac4b49..1afdeef41f0efc 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -234,7 +234,61 @@ def assign(self, dst: StackEffect, src: StackEffect): def cast(self, dst: StackEffect, src: StackEffect) -> str: return f"({dst.type or 'PyObject *'})" if src.type != dst.type else "" -INSTRUCTION_FLAGS = ['HAS_ARG', 'HAS_CONST', 'HAS_NAME', 'HAS_JUMP'] +@dataclasses.dataclass +class InstructionFlags: + """Construct and manipulate instruction flags""" + + HAS_ARG_FLAG: bool + HAS_CONST_FLAG: bool + HAS_NAME_FLAG: bool + HAS_JUMP_FLAG: bool + + def __post_init__(self): + self.bitmask = { + name : (1 << i) for i, name in enumerate(self.names()) + } + + @staticmethod + def fromInstruction(instr: "AnyInstruction"): + return InstructionFlags( + HAS_ARG_FLAG=variable_used(instr, "oparg"), + HAS_CONST_FLAG=variable_used(instr, "FRAME_CO_CONSTS"), + HAS_NAME_FLAG=variable_used(instr, "FRAME_CO_NAMES"), + HAS_JUMP_FLAG=variable_used(instr, "JUMPBY"), + ) + + @staticmethod + def newEmpty(): + return InstructionFlags(False, False, False, False) + + def add(self, other: "InstructionFlags") -> None: + for name, value in dataclasses.asdict(other).items(): + if value: + setattr(self, name, value) + + def names(self, value=None): + if value is None: + return dataclasses.asdict(self).keys() + return [n for n, v in dataclasses.asdict(self).items() if v == value] + + def bitmap(self) -> int: + flags = 0 + for name in self.names(): + if getattr(self, name): + flags |= self.bitmask[name] + return flags + + @classmethod + def emit_macros(cls, out: Formatter): + flags = cls.newEmpty() + for name, value in flags.bitmask.items(): + out.emit(f"#define {name} ({value})"); + + for name, value in flags.bitmask.items(): + out.emit( + f"#define OPCODE_{name[:-len('_FLAG')]}(OP) " + f"(_PyOpcode_opcode_metadata[(OP)].flags & ({name}))") + @dataclasses.dataclass class Instruction: @@ -256,7 +310,7 @@ class Instruction: output_effects: list[StackEffect] unmoved_names: frozenset[str] instr_fmt: str - flags: int + instr_flags: InstructionFlags # Set later family: parser.Family | None = None @@ -285,18 +339,10 @@ def __init__(self, inst: parser.InstDef): else: break self.unmoved_names = frozenset(unmoved_names) - flag_data = { - 'HAS_ARG' : variable_used(inst, "oparg"), - 'HAS_CONST': variable_used(inst, "FRAME_CO_CONSTS"), - 'HAS_NAME' : variable_used(inst, "FRAME_CO_NAMES"), - 'HAS_JUMP' : variable_used(inst, "JUMPBY"), - } - assert set(flag_data.keys()) == set(INSTRUCTION_FLAGS) - self.flags = 0 - for i, name in enumerate(INSTRUCTION_FLAGS): - self.flags |= (1< MacroInstruction: sp = initial_sp parts: list[Component | parser.CacheEffect] = [] format = "IB" - flags = 0 + flags = InstructionFlags.newEmpty() cache = "C" for component in components: match component: @@ -803,7 +848,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: for _ in range(ce.size): format += cache cache = "0" - flags |= instr.flags + flags.add(instr.instr_flags) case _: typing.assert_never(component) final_sp = sp @@ -817,9 +862,8 @@ def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction: # Make sure the targets have the same fmt fmts = list(set([t.instr_fmt for t in targets])) assert(len(fmts) == 1) - flags_list = list(set([t.flags for t in targets])) - assert(len(flags_list) == 1) - return PseudoInstruction(pseudo.name, targets, fmts[0], flags_list[0]) + assert(len(list(set([t.instr_flags.bitmap() for t in targets]))) == 1) + return PseudoInstruction(pseudo.name, targets, fmts[0], targets[0].instr_flags) def analyze_instruction( self, instr: Instruction, stack: list[StackEffect], sp: int @@ -1067,13 +1111,8 @@ def write_metadata(self) -> None: # Write type definitions self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") - for i, flag in enumerate(INSTRUCTION_FLAGS): - self.out.emit(f"#define {flag}{INSTR_FLAG_SUFFIX} ({1 << i})"); - for flag in INSTRUCTION_FLAGS: - flag_name = f"{flag}{INSTR_FLAG_SUFFIX}" - self.out.emit( - f"#define OPCODE_{flag}(OP) " - f"(_PyOpcode_opcode_metadata[(OP)].flags & ({flag_name}))") + + InstructionFlags.emit_macros(self.out) self.out.emit("struct opcode_metadata {") with self.out.indent(): @@ -1153,25 +1192,28 @@ def write_pseudo_instrs(self) -> None: self.out.emit(f" ((OP) == {op}) || \\") self.out.emit(f" 0") - def emit_metadata_entry(self, name: str, fmt: str, flags: int) -> None: - flags_strs = [f"{name}{INSTR_FLAG_SUFFIX}" - for i, name in enumerate(INSTRUCTION_FLAGS) if (flags & (1< None: + flag_names = flags.names(value=True) + if not flag_names: + flag_names.append("0") self.out.emit( - f" [{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt}, {flags_s} }}," + f" [{name}] = {{ true, {INSTR_FMT_PREFIX}{fmt}," + f" {' | '.join(flag_names)} }}," ) def write_metadata_for_inst(self, instr: Instruction) -> None: """Write metadata for a single instruction.""" - self.emit_metadata_entry(instr.name, instr.instr_fmt, instr.flags) + self.emit_metadata_entry(instr.name, instr.instr_fmt, instr.instr_flags) def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" - self.emit_metadata_entry(mac.name, mac.instr_fmt, mac.flags) + self.emit_metadata_entry(mac.name, mac.instr_fmt, mac.instr_flags) def write_metadata_for_pseudo(self, ps: PseudoInstruction) -> None: """Write metadata for a macro-instruction.""" - self.emit_metadata_entry(ps.name, ps.instr_fmt, ps.flags) + self.emit_metadata_entry(ps.name, ps.instr_fmt, ps.instr_flags) def write_instructions(self) -> None: """Write instructions to output file.""" From 04492cbc9aa45ac2c12d22083c406a0364c39f5b Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 22 Jun 2023 09:48:19 +0100 Subject: [PATCH 109/446] GH-91095: Specialize calls to normal Python classes. (GH-99331) --- Include/cpython/object.h | 1 + Include/internal/pycore_frame.h | 24 ++ Include/internal/pycore_object.h | 2 + Include/internal/pycore_opcode.h | 46 ++-- Include/opcode.h | 108 ++++---- Lib/_opcode_metadata.py | 1 + Lib/opcode.py | 1 + Lib/test/test_sys.py | 2 +- Lib/test/test_sys_settrace.py | 24 +- ...2-11-10-13-04-35.gh-issue-91095.4E3Pwn.rst | 11 + Objects/dictobject.c | 7 +- Objects/typeobject.c | 20 ++ Python/bytecodes.c | 63 +++++ Python/ceval.c | 4 +- Python/compile.c | 3 + Python/generated_cases.c.h | 230 ++++++++++++------ Python/instrumentation.c | 2 +- Python/opcode_metadata.h | 10 + Python/opcode_targets.h | 42 ++-- Python/specialize.c | 99 +++++++- 20 files changed, 511 insertions(+), 189 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-10-13-04-35.gh-issue-91095.4E3Pwn.rst diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 7d69231aaa3119..71d268fae1a6dc 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -246,6 +246,7 @@ struct _specialization_cache { // *args nor **kwargs (as required by BINARY_SUBSCR_GETITEM): PyObject *getitem; uint32_t getitem_version; + PyObject *init; }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index caff86c64acfe2..952a96009dda6c 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -272,6 +272,30 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l return new_frame; } +/* Pushes a trampoline frame without checking for space. + * Must be guarded by _PyThreadState_HasStackSpace() */ +static inline _PyInterpreterFrame * +_PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int stackdepth, int prev_instr) +{ + CALL_STAT_INC(frames_pushed); + _PyInterpreterFrame *frame = (_PyInterpreterFrame *)tstate->datastack_top; + tstate->datastack_top += code->co_framesize; + assert(tstate->datastack_top < tstate->datastack_limit); + frame->f_funcobj = Py_None; + frame->f_executable = Py_NewRef(code); +#ifdef Py_DEBUG + frame->f_builtins = NULL; + frame->f_globals = NULL; +#endif + frame->f_locals = NULL; + frame->stacktop = code->co_nlocalsplus + stackdepth; + frame->frame_obj = NULL; + frame->prev_instr = _PyCode_CODE(code) + prev_instr; + frame->owner = FRAME_OWNED_BY_THREAD; + frame->return_offset = 0; + return frame; +} + static inline PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) { diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 3ac7e89bbf5345..2358f48738a905 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -355,8 +355,10 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) { } extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems); +PyObject *_PyType_NewManagedObject(PyTypeObject *type); extern int _PyObject_InitializeDict(PyObject *obj); +int _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp); extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values, PyObject *name, PyObject *value); PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values, diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 6b269e3c02d6c1..cab5b587eda87d 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -68,6 +68,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL_INTRINSIC_1] = CALL_INTRINSIC_1, [CALL_INTRINSIC_2] = CALL_INTRINSIC_2, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, + [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = CALL, [CALL_NO_KW_BUILTIN_FAST] = CALL, [CALL_NO_KW_BUILTIN_O] = CALL, [CALL_NO_KW_ISINSTANCE] = CALL, @@ -104,6 +105,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [END_FOR] = END_FOR, [END_SEND] = END_SEND, [ENTER_EXECUTOR] = ENTER_EXECUTOR, + [EXIT_INIT_CHECK] = EXIT_INIT_CHECK, [EXTENDED_ARG] = EXTENDED_ARG, [FORMAT_SIMPLE] = FORMAT_SIMPLE, [FORMAT_WITH_SPEC] = FORMAT_WITH_SPEC, @@ -251,39 +253,39 @@ static const char *const _PyOpcode_OpName[267] = { [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [UNARY_INVERT] = "UNARY_INVERT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [EXIT_INIT_CHECK] = "EXIT_INIT_CHECK", [RESERVED] = "RESERVED", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [MAKE_FUNCTION] = "MAKE_FUNCTION", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", - [SEND_GEN] = "SEND_GEN", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [SEND_GEN] = "SEND_GEN", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [FORMAT_SIMPLE] = "FORMAT_SIMPLE", [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", - [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -291,39 +293,39 @@ static const char *const _PyOpcode_OpName[267] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [COMPARE_OP_INT] = "COMPARE_OP_INT", - [COMPARE_OP_STR] = "COMPARE_OP_STR", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [RETURN_VALUE] = "RETURN_VALUE", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [LOAD_LOCALS] = "LOAD_LOCALS", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -346,9 +348,9 @@ static const char *const _PyOpcode_OpName[267] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -367,7 +369,7 @@ static const char *const _PyOpcode_OpName[267] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", @@ -383,26 +385,26 @@ static const char *const _PyOpcode_OpName[267] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", [CONVERT_VALUE] = "CONVERT_VALUE", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [166] = "<166>", - [167] = "<167>", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT", [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST", [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST", [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST", @@ -506,8 +508,6 @@ static const char *const _PyOpcode_OpName[267] = { #endif #define EXTRA_CASES \ - case 166: \ - case 167: \ case 178: \ case 179: \ case 180: \ diff --git a/Include/opcode.h b/Include/opcode.h index 39bb70a8f2842f..3fe4fc0bb3404f 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -18,6 +18,7 @@ extern "C" { #define UNARY_NEGATIVE 11 #define UNARY_NOT 12 #define UNARY_INVERT 15 +#define EXIT_INIT_CHECK 16 #define RESERVED 17 #define MAKE_FUNCTION 24 #define BINARY_SUBSCR 25 @@ -164,59 +165,60 @@ extern "C" { #define BINARY_OP_MULTIPLY_FLOAT 10 #define BINARY_OP_ADD_FLOAT 13 #define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_ADD_UNICODE 16 -#define BINARY_OP_INPLACE_ADD_UNICODE 18 -#define BINARY_SUBSCR_DICT 19 -#define BINARY_SUBSCR_GETITEM 20 -#define BINARY_SUBSCR_LIST_INT 21 -#define BINARY_SUBSCR_TUPLE_INT 22 -#define STORE_SUBSCR_DICT 23 -#define STORE_SUBSCR_LIST_INT 28 -#define SEND_GEN 29 -#define UNPACK_SEQUENCE_TWO_TUPLE 34 -#define UNPACK_SEQUENCE_TUPLE 38 -#define UNPACK_SEQUENCE_LIST 39 -#define STORE_ATTR_INSTANCE_VALUE 42 -#define STORE_ATTR_SLOT 43 -#define STORE_ATTR_WITH_HINT 44 -#define LOAD_GLOBAL_MODULE 45 -#define LOAD_GLOBAL_BUILTIN 46 -#define LOAD_SUPER_ATTR_ATTR 47 -#define LOAD_SUPER_ATTR_METHOD 48 -#define LOAD_ATTR_INSTANCE_VALUE 56 -#define LOAD_ATTR_MODULE 57 -#define LOAD_ATTR_WITH_HINT 58 -#define LOAD_ATTR_SLOT 59 -#define LOAD_ATTR_CLASS 62 -#define LOAD_ATTR_PROPERTY 63 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 64 -#define LOAD_ATTR_METHOD_WITH_VALUES 65 -#define LOAD_ATTR_METHOD_NO_DICT 66 -#define LOAD_ATTR_METHOD_LAZY_DICT 67 -#define COMPARE_OP_FLOAT 70 -#define COMPARE_OP_INT 72 -#define COMPARE_OP_STR 73 -#define FOR_ITER_LIST 76 -#define FOR_ITER_TUPLE 77 -#define FOR_ITER_RANGE 78 -#define FOR_ITER_GEN 79 -#define CALL_BOUND_METHOD_EXACT_ARGS 80 -#define CALL_PY_EXACT_ARGS 81 -#define CALL_PY_WITH_DEFAULTS 82 -#define CALL_NO_KW_TYPE_1 84 -#define CALL_NO_KW_STR_1 86 -#define CALL_NO_KW_TUPLE_1 88 -#define CALL_BUILTIN_CLASS 111 -#define CALL_NO_KW_BUILTIN_O 112 -#define CALL_NO_KW_BUILTIN_FAST 113 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 132 -#define CALL_NO_KW_LEN 148 -#define CALL_NO_KW_ISINSTANCE 153 -#define CALL_NO_KW_LIST_APPEND 154 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 155 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 159 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 160 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 161 +#define BINARY_OP_ADD_UNICODE 18 +#define BINARY_OP_INPLACE_ADD_UNICODE 19 +#define BINARY_SUBSCR_DICT 20 +#define BINARY_SUBSCR_GETITEM 21 +#define BINARY_SUBSCR_LIST_INT 22 +#define BINARY_SUBSCR_TUPLE_INT 23 +#define STORE_SUBSCR_DICT 28 +#define STORE_SUBSCR_LIST_INT 29 +#define SEND_GEN 34 +#define UNPACK_SEQUENCE_TWO_TUPLE 38 +#define UNPACK_SEQUENCE_TUPLE 39 +#define UNPACK_SEQUENCE_LIST 42 +#define STORE_ATTR_INSTANCE_VALUE 43 +#define STORE_ATTR_SLOT 44 +#define STORE_ATTR_WITH_HINT 45 +#define LOAD_GLOBAL_MODULE 46 +#define LOAD_GLOBAL_BUILTIN 47 +#define LOAD_SUPER_ATTR_ATTR 48 +#define LOAD_SUPER_ATTR_METHOD 56 +#define LOAD_ATTR_INSTANCE_VALUE 57 +#define LOAD_ATTR_MODULE 58 +#define LOAD_ATTR_WITH_HINT 59 +#define LOAD_ATTR_SLOT 62 +#define LOAD_ATTR_CLASS 63 +#define LOAD_ATTR_PROPERTY 64 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 +#define LOAD_ATTR_METHOD_WITH_VALUES 66 +#define LOAD_ATTR_METHOD_NO_DICT 67 +#define LOAD_ATTR_METHOD_LAZY_DICT 70 +#define COMPARE_OP_FLOAT 72 +#define COMPARE_OP_INT 73 +#define COMPARE_OP_STR 76 +#define FOR_ITER_LIST 77 +#define FOR_ITER_TUPLE 78 +#define FOR_ITER_RANGE 79 +#define FOR_ITER_GEN 80 +#define CALL_BOUND_METHOD_EXACT_ARGS 81 +#define CALL_PY_EXACT_ARGS 82 +#define CALL_PY_WITH_DEFAULTS 84 +#define CALL_NO_KW_TYPE_1 86 +#define CALL_NO_KW_STR_1 88 +#define CALL_NO_KW_TUPLE_1 111 +#define CALL_BUILTIN_CLASS 112 +#define CALL_NO_KW_BUILTIN_O 113 +#define CALL_NO_KW_BUILTIN_FAST 132 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 148 +#define CALL_NO_KW_LEN 153 +#define CALL_NO_KW_ISINSTANCE 154 +#define CALL_NO_KW_LIST_APPEND 155 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 159 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 160 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 161 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 166 +#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 167 #define NB_ADD 0 #define NB_AND 1 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index 92ed4037d8ddb7..c0a68256802c37 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -85,6 +85,7 @@ "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + "CALL_NO_KW_ALLOC_AND_ENTER_INIT", ], } diff --git a/Lib/opcode.py b/Lib/opcode.py index ed01d2cdad9ebf..392464ddab9728 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -97,6 +97,7 @@ def pseudo_op(name, op, real_ops): def_op('UNARY_NOT', 12) def_op('UNARY_INVERT', 15) +def_op('EXIT_INIT_CHECK', 16) # We reserve 17 as it is the initial value for the specializing counter # This helps us catch cases where we attempt to execute a cache. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index d81501f6f1df6a..37f75ad54387a0 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1557,7 +1557,7 @@ def delx(self): del self.__x '10P' # PySequenceMethods '2P' # PyBufferProcs '6P' - '1PI' # Specializer cache + '1PIP' # Specializer cache ) class newstyleclass(object): pass # Separate block for PyDictKeysObject with 8 keys and 5 entries diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 5603c3cdbf3c5e..4462b5c712d662 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -1614,8 +1614,30 @@ def func(): self.run_and_compare(func, EXPECTED_EVENTS) - def test_settrace_error(self): + def test_correct_tracing_quickened_call_class_init(self): + + class C: + def __init__(self): + self + + def func(): + C() + EXPECTED_EVENTS = [ + (0, 'call'), + (1, 'line'), + (-3, 'call'), + (-2, 'line'), + (-2, 'return'), + (1, 'return')] + + self.run_and_compare(func, EXPECTED_EVENTS) + # Quicken + for _ in range(100): + func() + self.run_and_compare(func, EXPECTED_EVENTS) + + def test_settrace_error(self): raised = False def error_once(frame, event, arg): nonlocal raised diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-10-13-04-35.gh-issue-91095.4E3Pwn.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-10-13-04-35.gh-issue-91095.4E3Pwn.rst new file mode 100644 index 00000000000000..5633097f4a3fdd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-10-13-04-35.gh-issue-91095.4E3Pwn.rst @@ -0,0 +1,11 @@ +Specializes calls to most Python classes. Specifically, any class that +inherits from ``object``, or another Python class, and does not override +``__new__``. + +The specialized instruction does the following: + +1. Creates the object (by calling ``object.__new__``) +2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) +3. Pushes the frame for ``__init__`` to the frame stack + +Speeds up the instantiation of most Python classes. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 254cd9ad2f9bda..194081db2f290a 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5334,11 +5334,10 @@ _PyDict_NewKeysForClass(void) #define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys) -static int -init_inline_values(PyObject *obj, PyTypeObject *tp) +int +_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp) { assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); - // assert(type->tp_dictoffset > 0); -- TO DO Update this assert. assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictKeysObject *keys = CACHED_KEYS(tp); assert(keys != NULL); @@ -5370,7 +5369,7 @@ _PyObject_InitializeDict(PyObject *obj) } if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) { OBJECT_STAT_INC(new_values); - return init_inline_values(obj, tp); + return _PyObject_InitInlineValues(obj, tp); } PyObject *dict; if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cbba6f0fa80d12..d427ecd50a76fc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1681,6 +1681,26 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) return obj; } +PyObject * +_PyType_NewManagedObject(PyTypeObject *type) +{ + assert(type->tp_flags & Py_TPFLAGS_MANAGED_DICT); + assert(_PyType_IS_GC(type)); + assert(type->tp_new == PyBaseObject_Type.tp_new); + assert(type->tp_alloc == PyType_GenericAlloc); + assert(type->tp_itemsize == 0); + PyObject *obj = PyType_GenericAlloc(type, 0); + if (obj == NULL) { + return PyErr_NoMemory(); + } + _PyObject_DictOrValuesPointer(obj)->dict = NULL; + if (_PyObject_InitInlineValues(obj, type)) { + Py_DECREF(obj); + return NULL; + } + return obj; +} + PyObject * _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems) { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a7acff65e13e3a..3ef8ed0ccaafdc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2685,6 +2685,7 @@ dummy_func( CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + CALL_NO_KW_ALLOC_AND_ENTER_INIT, }; // On entry, the stack is either @@ -2900,6 +2901,68 @@ dummy_func( CHECK_EVAL_BREAKER(); } + inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, null, callable, args[oparg] -- unused)) { + /* This instruction does the following: + * 1. Creates the object (by calling ``object.__new__``) + * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) + * 3. Pushes the frame for ``__init__`` to the frame stack + * */ + assert(kwnames == NULL); + _PyCallCache *cache = (_PyCallCache *)next_instr; + DEOPT_IF(null != NULL, CALL); + DEOPT_IF(!PyType_Check(callable), CALL); + PyTypeObject *tp = (PyTypeObject *)callable; + DEOPT_IF(tp->tp_version_tag != read_u32(cache->func_version), CALL); + PyHeapTypeObject *cls = (PyHeapTypeObject *)callable; + PyFunctionObject *init = (PyFunctionObject *)cls->_spec_cache.init; + PyCodeObject *code = (PyCodeObject *)init->func_code; + DEOPT_IF(code->co_argcount != oparg+1, CALL); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL); + STAT_INC(CALL, hit); + PyObject *self = _PyType_NewManagedObject(tp); + if (self == NULL) { + goto error; + } + Py_DECREF(tp); + if (_Py_EnterRecursivePy(tstate)) { + goto exit_unwind; + } + _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( + tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); + assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); + /* Push self onto stack of shim */ + Py_INCREF(self); + shim->localsplus[0] = self; + Py_INCREF(init); + _PyInterpreterFrame *init_frame = _PyFrame_PushUnchecked(tstate, init, oparg+1); + /* Copy self followed by args to __init__ frame */ + init_frame->localsplus[0] = self; + for (int i = 0; i < oparg; i++) { + init_frame->localsplus[i+1] = args[i]; + } + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); + frame->prev_instr = next_instr - 1; + frame->return_offset = 0; + STACK_SHRINK(oparg+2); + _PyFrame_SetStackPointer(frame, stack_pointer); + /* Link frames */ + init_frame->previous = shim; + shim->previous = frame; + frame = cframe.current_frame = init_frame; + CALL_STAT_INC(inlined_py_calls); + goto start_frame; + } + + inst(EXIT_INIT_CHECK, (should_be_none -- )) { + assert(STACK_LEVEL() == 2); + if (should_be_none != Py_None) { + PyErr_Format(PyExc_TypeError, + "__init__() should return None, not '%.200s'", + Py_TYPE(should_be_none)->tp_name); + goto error; + } + } + inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { int is_meth = method != NULL; int total_args = oparg; diff --git a/Python/ceval.c b/Python/ceval.c index b1ac4de3f625da..53107018978c0b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -641,6 +641,8 @@ static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { { .op.code = RESUME, .op.arg = 0 } }; +extern const struct _PyCode_DEF(8) _Py_InitCleanup; + /* Disable unused label warnings. They are handy for debugging, even if computed gotos aren't used. */ @@ -746,7 +748,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #ifdef LLTRACE { - if (frame != &entry_frame) { + if (frame != &entry_frame && GLOBALS()) { int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__)); if (r < 0) { goto exit_unwind; diff --git a/Python/compile.c b/Python/compile.c index 69468f755a1d26..5a0560521b99d5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -825,6 +825,9 @@ stack_effect(int opcode, int oparg, int jump) case JUMP_NO_INTERRUPT: return 0; + case EXIT_INIT_CHECK: + return -1; + /* Exception handling pseudo-instructions */ case SETUP_FINALLY: /* 0 in the normal flow. diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 717b29e811d309..11ca535adfb19b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3765,7 +3765,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2698 "Python/bytecodes.c" + #line 2699 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3859,7 +3859,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2786 "Python/bytecodes.c" + #line 2787 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3878,7 +3878,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2798 "Python/bytecodes.c" + #line 2799 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3912,7 +3912,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2826 "Python/bytecodes.c" + #line 2827 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3956,7 +3956,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2864 "Python/bytecodes.c" + #line 2865 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3979,7 +3979,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2876 "Python/bytecodes.c" + #line 2877 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4004,7 +4004,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2890 "Python/bytecodes.c" + #line 2891 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4024,12 +4024,84 @@ DISPATCH(); } + TARGET(CALL_NO_KW_ALLOC_AND_ENTER_INIT) { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *null = stack_pointer[-(2 + oparg)]; + #line 2905 "Python/bytecodes.c" + /* This instruction does the following: + * 1. Creates the object (by calling ``object.__new__``) + * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) + * 3. Pushes the frame for ``__init__`` to the frame stack + * */ + assert(kwnames == NULL); + _PyCallCache *cache = (_PyCallCache *)next_instr; + DEOPT_IF(null != NULL, CALL); + DEOPT_IF(!PyType_Check(callable), CALL); + PyTypeObject *tp = (PyTypeObject *)callable; + DEOPT_IF(tp->tp_version_tag != read_u32(cache->func_version), CALL); + PyHeapTypeObject *cls = (PyHeapTypeObject *)callable; + PyFunctionObject *init = (PyFunctionObject *)cls->_spec_cache.init; + PyCodeObject *code = (PyCodeObject *)init->func_code; + DEOPT_IF(code->co_argcount != oparg+1, CALL); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize + _Py_InitCleanup.co_framesize), CALL); + STAT_INC(CALL, hit); + PyObject *self = _PyType_NewManagedObject(tp); + if (self == NULL) { + goto error; + } + Py_DECREF(tp); + if (_Py_EnterRecursivePy(tstate)) { + goto exit_unwind; + } + _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( + tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); + assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); + /* Push self onto stack of shim */ + Py_INCREF(self); + shim->localsplus[0] = self; + Py_INCREF(init); + _PyInterpreterFrame *init_frame = _PyFrame_PushUnchecked(tstate, init, oparg+1); + /* Copy self followed by args to __init__ frame */ + init_frame->localsplus[0] = self; + for (int i = 0; i < oparg; i++) { + init_frame->localsplus[i+1] = args[i]; + } + SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); + frame->prev_instr = next_instr - 1; + frame->return_offset = 0; + STACK_SHRINK(oparg+2); + _PyFrame_SetStackPointer(frame, stack_pointer); + /* Link frames */ + init_frame->previous = shim; + shim->previous = frame; + frame = cframe.current_frame = init_frame; + CALL_STAT_INC(inlined_py_calls); + goto start_frame; + #line 4082 "Python/generated_cases.c.h" + } + + TARGET(EXIT_INIT_CHECK) { + PyObject *should_be_none = stack_pointer[-1]; + #line 2957 "Python/bytecodes.c" + assert(STACK_LEVEL() == 2); + if (should_be_none != Py_None) { + PyErr_Format(PyExc_TypeError, + "__init__() should return None, not '%.200s'", + Py_TYPE(should_be_none)->tp_name); + goto error; + } + #line 4095 "Python/generated_cases.c.h" + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(CALL_BUILTIN_CLASS) { PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2904 "Python/bytecodes.c" + #line 2967 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4051,7 +4123,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4055 "Python/generated_cases.c.h" + #line 4127 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4065,7 +4137,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2929 "Python/bytecodes.c" + #line 2992 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4093,7 +4165,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4097 "Python/generated_cases.c.h" + #line 4169 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4107,7 +4179,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2960 "Python/bytecodes.c" + #line 3023 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4139,7 +4211,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4143 "Python/generated_cases.c.h" + #line 4215 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4153,7 +4225,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2995 "Python/bytecodes.c" + #line 3058 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4185,7 +4257,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4189 "Python/generated_cases.c.h" + #line 4261 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4199,7 +4271,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3030 "Python/bytecodes.c" + #line 3093 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4224,7 +4296,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4228 "Python/generated_cases.c.h" + #line 4300 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4237,7 +4309,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3057 "Python/bytecodes.c" + #line 3120 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4264,7 +4336,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4268 "Python/generated_cases.c.h" + #line 4340 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4276,7 +4348,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3087 "Python/bytecodes.c" + #line 3150 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4294,14 +4366,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4298 "Python/generated_cases.c.h" + #line 4370 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3107 "Python/bytecodes.c" + #line 3170 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4332,7 +4404,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4336 "Python/generated_cases.c.h" + #line 4408 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4345,7 +4417,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3141 "Python/bytecodes.c" + #line 3204 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4374,7 +4446,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4378 "Python/generated_cases.c.h" + #line 4450 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4387,7 +4459,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3173 "Python/bytecodes.c" + #line 3236 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4416,7 +4488,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4420 "Python/generated_cases.c.h" + #line 4492 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4429,7 +4501,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3205 "Python/bytecodes.c" + #line 3268 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4457,7 +4529,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4461 "Python/generated_cases.c.h" + #line 4533 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4467,9 +4539,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3236 "Python/bytecodes.c" + #line 3299 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4473 "Python/generated_cases.c.h" + #line 4545 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4478,7 +4550,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3240 "Python/bytecodes.c" + #line 3303 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4540,14 +4612,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4544 "Python/generated_cases.c.h" + #line 4616 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3302 "Python/bytecodes.c" + #line 3365 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4551 "Python/generated_cases.c.h" + #line 4623 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4558,7 +4630,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3308 "Python/bytecodes.c" + #line 3371 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4570,7 +4642,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4574 "Python/generated_cases.c.h" + #line 4646 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4578,7 +4650,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3322 "Python/bytecodes.c" + #line 3385 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4603,14 +4675,14 @@ default: Py_UNREACHABLE(); } - #line 4607 "Python/generated_cases.c.h" + #line 4679 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3349 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4631,7 +4703,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4635 "Python/generated_cases.c.h" + #line 4707 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4639,15 +4711,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3372 "Python/bytecodes.c" + #line 3435 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4645 "Python/generated_cases.c.h" + #line 4717 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3374 "Python/bytecodes.c" + #line 3437 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4651 "Python/generated_cases.c.h" + #line 4723 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4657,14 +4729,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3378 "Python/bytecodes.c" + #line 3441 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4668 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4672,7 +4744,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3387 "Python/bytecodes.c" + #line 3450 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4683,7 +4755,7 @@ else { res = value; } - #line 4687 "Python/generated_cases.c.h" + #line 4759 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4692,12 +4764,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3400 "Python/bytecodes.c" + #line 3463 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4701 "Python/generated_cases.c.h" + #line 4773 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4706,10 +4778,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3407 "Python/bytecodes.c" + #line 3470 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4713 "Python/generated_cases.c.h" + #line 4785 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4721,7 +4793,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3412 "Python/bytecodes.c" + #line 3475 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4736,12 +4808,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4740 "Python/generated_cases.c.h" + #line 4812 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3427 "Python/bytecodes.c" + #line 3490 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4745 "Python/generated_cases.c.h" + #line 4817 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4751,16 +4823,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3432 "Python/bytecodes.c" + #line 3495 "Python/bytecodes.c" assert(oparg >= 2); - #line 4757 "Python/generated_cases.c.h" + #line 4829 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3436 "Python/bytecodes.c" + #line 3499 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4772,26 +4844,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4776 "Python/generated_cases.c.h" + #line 4848 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3450 "Python/bytecodes.c" + #line 3513 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4782 "Python/generated_cases.c.h" + #line 4854 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3454 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4789 "Python/generated_cases.c.h" + #line 4861 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3459 "Python/bytecodes.c" + #line 3522 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4800,12 +4872,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4804 "Python/generated_cases.c.h" + #line 4876 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3470 "Python/bytecodes.c" + #line 3533 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4814,12 +4886,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4818 "Python/generated_cases.c.h" + #line 4890 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3481 "Python/bytecodes.c" + #line 3544 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4831,12 +4903,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4835 "Python/generated_cases.c.h" + #line 4907 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3495 "Python/bytecodes.c" + #line 3558 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4848,30 +4920,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4852 "Python/generated_cases.c.h" + #line 4924 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3509 "Python/bytecodes.c" + #line 3572 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4863 "Python/generated_cases.c.h" + #line 4935 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3517 "Python/bytecodes.c" + #line 3580 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4870 "Python/generated_cases.c.h" + #line 4942 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3522 "Python/bytecodes.c" + #line 3585 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4877 "Python/generated_cases.c.h" + #line 4949 "Python/generated_cases.c.h" } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index fcaccc022c8b2d..524a82c076e99d 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1526,7 +1526,7 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) return 0; } /* Insert instrumentation */ - for (int i = 0; i < code_len; i+= _PyInstruction_GetLength(code, i)) { + for (int i = code->_co_firsttraceable; i < code_len; i+= _PyInstruction_GetLength(code, i)) { _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; CHECK(instr->op.code != 0); int base_opcode = _Py_GetBaseOpcode(code, i); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index aa1db721d1ae71..421d9795e7da76 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -368,6 +368,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return oparg + 2; case CALL_NO_KW_TUPLE_1: return oparg + 2; + case CALL_NO_KW_ALLOC_AND_ENTER_INIT: + return oparg + 2; + case EXIT_INIT_CHECK: + return 1; case CALL_BUILTIN_CLASS: return oparg + 2; case CALL_NO_KW_BUILTIN_O: @@ -790,6 +794,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case CALL_NO_KW_TUPLE_1: return 1; + case CALL_NO_KW_ALLOC_AND_ENTER_INIT: + return 1; + case EXIT_INIT_CHECK: + return 0; case CALL_BUILTIN_CLASS: return 1; case CALL_NO_KW_BUILTIN_O: @@ -1057,6 +1065,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, + [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, 0 }, [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 4de4bf0608f35e..781d72fa7f5333 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -15,39 +15,39 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_UNARY_INVERT, - &&TARGET_BINARY_OP_ADD_UNICODE, + &&TARGET_EXIT_INIT_CHECK, &&TARGET_RESERVED, + &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_MAKE_FUNCTION, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, - &&TARGET_SEND_GEN, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&TARGET_SEND_GEN, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_FORMAT_SIMPLE, &&TARGET_FORMAT_WITH_SPEC, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_SUPER_ATTR_ATTR, - &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_LOAD_ATTR_SLOT, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_COMPARE_OP_FLOAT, + &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, - &&TARGET_COMPARE_OP_STR, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_COMPARE_OP_STR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_CALL_PY_EXACT_ARGS, - &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_RETURN_VALUE, - &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_CALL_NO_KW_STR_1, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_LOAD_LOCALS, - &&TARGET_CALL_NO_KW_TUPLE_1, + &&TARGET_CALL_NO_KW_STR_1, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, + &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_CALL_NO_KW_BUILTIN_O, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,7 +131,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, @@ -147,26 +147,26 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_CALL_NO_KW_LEN, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_CALL_NO_KW_LEN, &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LIST_APPEND, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_CONVERT_VALUE, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT, &&TARGET_LOAD_FAST_LOAD_FAST, &&TARGET_STORE_FAST_LOAD_FAST, &&TARGET_STORE_FAST_STORE_FAST, diff --git a/Python/specialize.c b/Python/specialize.c index 44b14c5952315f..0006aa733bd6cb 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -391,7 +391,7 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS 18 #define SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS 19 #define SPEC_FAIL_CALL_BAD_CALL_FLAGS 20 -#define SPEC_FAIL_CALL_PYTHON_CLASS 21 +#define SPEC_FAIL_CALL_INIT_NOT_PYTHON 21 #define SPEC_FAIL_CALL_PEP_523 22 #define SPEC_FAIL_CALL_BOUND_METHOD 23 #define SPEC_FAIL_CALL_STR 24 @@ -400,6 +400,7 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_KWNAMES 27 #define SPEC_FAIL_CALL_METHOD_WRAPPER 28 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 +#define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30 /* COMPARE_OP */ #define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 @@ -1491,15 +1492,46 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins cache->counter = adaptive_counter_cooldown(); } +/* Returns a borrowed reference. + * The reference is only valid if guarded by a type version check. + */ +static PyFunctionObject * +get_init_for_simple_managed_python_class(PyTypeObject *tp) +{ + assert(tp->tp_new == PyBaseObject_Type.tp_new); + if (tp->tp_alloc != PyType_GenericAlloc) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OVERRIDDEN); + return NULL; + } + if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_NO_DICT); + return NULL; + } + if (!(tp->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + /* Is this possible? */ + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_EXPECTED_ERROR); + return NULL; + } + PyObject *init = _PyType_Lookup(tp, &_Py_ID(__init__)); + if (init == NULL || !PyFunction_Check(init)) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_PYTHON); + return NULL; + } + int kind = function_kind((PyCodeObject *)PyFunction_GET_CODE(init)); + if (kind != SIMPLE_FUNCTION) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_INIT_NOT_SIMPLE); + return NULL; + } + ((PyHeapTypeObject *)tp)->_spec_cache.init = init; + return (PyFunctionObject *)init; +} + static int specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames) { + assert(PyType_Check(callable)); PyTypeObject *tp = _PyType_CAST(callable); - if (tp->tp_new == PyBaseObject_Type.tp_new) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PYTHON_CLASS); - return -1; - } if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { int oparg = instr->op.arg; if (nargs == 1 && kwnames == NULL && oparg == 1) { @@ -1524,6 +1556,24 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SPEC_FAIL_CALL_STR : SPEC_FAIL_CALL_CLASS_NO_VECTORCALL); return -1; } + if (tp->tp_new == PyBaseObject_Type.tp_new) { + PyFunctionObject *init = get_init_for_simple_managed_python_class(tp); + if (init != NULL) { + if (((PyCodeObject *)init->func_code)->co_argcount != nargs+1) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); + return -1; + } + if (kwnames) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); + return -1; + } + _PyCallCache *cache = (_PyCallCache *)(instr + 1); + write_u32(cache->func_version, tp->tp_version_tag); + _Py_SET_OPCODE(*instr, CALL_NO_KW_ALLOC_AND_ENTER_INIT); + return 0; + } + return -1; + } SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE); return -1; } @@ -2229,3 +2279,42 @@ _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr) STAT_INC(SEND, success); cache->counter = adaptive_counter_cooldown(); } + +/* Code init cleanup. + * CALL_NO_KW_ALLOC_AND_ENTER_INIT will set up + * the frame to execute the EXIT_INIT_CHECK + * instruction. + * Ends with a RESUME so that it is not traced. + * This is used as a plain code object, not a function, + * so must not access globals or builtins. + */ + +#define NO_LOC_4 (128 | (PY_CODE_LOCATION_INFO_NONE << 3) | 3) + +static const PyBytesObject no_location = { + PyVarObject_HEAD_INIT(&PyBytes_Type, 1) + .ob_sval = { NO_LOC_4 } +}; + +const struct _PyCode_DEF(8) _Py_InitCleanup = { + _PyVarObject_HEAD_INIT(&PyCode_Type, 4) + .co_consts = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_names = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty), + .co_flags = CO_OPTIMIZED, + .co_localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty), + .co_filename = &_Py_ID(__init__), + .co_name = &_Py_ID(__init__), + .co_qualname = &_Py_ID(__init__), + .co_linetable = (PyObject *)&no_location, + ._co_firsttraceable = 4, + .co_stacksize = 2, + .co_framesize = 2 + FRAME_SPECIALS_SIZE, + .co_code_adaptive = { + NOP, 0, + EXIT_INIT_CHECK, 0, + RETURN_VALUE, 0, + RESUME, 0, + } +}; From a8006706f7d6e8825b90f1970beed7845d1d72ed Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Thu, 22 Jun 2023 14:35:51 +0100 Subject: [PATCH 110/446] GH-89812: Add `pathlib.UnsupportedOperation` (GH-105926) This new exception type is raised instead of `NotImplementedError` when a path operation is not supported. It can be raised from `Path.readlink()`, `symlink_to()`, `hardlink_to()`, `owner()` and `group()`. In a future version of pathlib, it will be raised by `AbstractPath` for these methods and others, such as `AbstractPath.mkdir()` and `unlink()`. --- Doc/library/pathlib.rst | 44 ++++++++++++++++++- Doc/whatsnew/3.13.rst | 4 ++ Lib/pathlib.py | 22 +++++++--- Lib/test/test_pathlib.py | 32 +++++++++++--- ...3-06-19-22-20-41.gh-issue-89812.z2l_e8.rst | 2 + 5 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-19-22-20-41.gh-issue-89812.z2l_e8.rst diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index ad801d5d7cdc4b..3a4e1e64685cb4 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -88,6 +88,17 @@ Opening a file:: '#!/bin/bash\n' +Exceptions +---------- + +.. exception:: UnsupportedOperation + + An exception inheriting :exc:`NotImplementedError` that is raised when an + unsupported operation is called on a path object. + + .. versionadded:: 3.13 + + .. _pure-paths: Pure paths @@ -752,6 +763,11 @@ calls on path objects. There are three ways to instantiate concrete paths: *pathsegments* is specified similarly to :class:`PurePath`. + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` on Windows. In previous versions, + :exc:`NotImplementedError` was raised instead. + + .. class:: WindowsPath(*pathsegments) A subclass of :class:`Path` and :class:`PureWindowsPath`, this class @@ -762,6 +778,11 @@ calls on path objects. There are three ways to instantiate concrete paths: *pathsegments* is specified similarly to :class:`PurePath`. + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` on non-Windows platforms. In previous + versions, :exc:`NotImplementedError` was raised instead. + + You can only instantiate the class flavour that corresponds to your system (allowing system calls on non-compatible path flavours could lead to bugs or failures in your application):: @@ -778,7 +799,7 @@ bugs or failures in your application):: File "", line 1, in File "pathlib.py", line 798, in __new__ % (cls.__name__,)) - NotImplementedError: cannot instantiate 'WindowsPath' on your system + UnsupportedOperation: cannot instantiate 'WindowsPath' on your system Methods @@ -952,6 +973,10 @@ call fails (for example because the path doesn't exist). Return the name of the group owning the file. :exc:`KeyError` is raised if the file's gid isn't found in the system database. + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` if the :mod:`grp` module is not + available. In previous versions, :exc:`NotImplementedError` was raised. + .. method:: Path.is_dir() @@ -1210,6 +1235,10 @@ call fails (for example because the path doesn't exist). Return the name of the user owning the file. :exc:`KeyError` is raised if the file's uid isn't found in the system database. + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` if the :mod:`pwd` module is not + available. In previous versions, :exc:`NotImplementedError` was raised. + .. method:: Path.read_bytes() @@ -1252,6 +1281,10 @@ call fails (for example because the path doesn't exist). .. versionadded:: 3.9 + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` if :func:`os.readlink` is not + available. In previous versions, :exc:`NotImplementedError` was raised. + .. method:: Path.rename(target) @@ -1414,6 +1447,11 @@ call fails (for example because the path doesn't exist). The order of arguments (link, target) is the reverse of :func:`os.symlink`'s. + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` if :func:`os.symlink` is not + available. In previous versions, :exc:`NotImplementedError` was raised. + + .. method:: Path.hardlink_to(target) Make this path a hard link to the same file as *target*. @@ -1424,6 +1462,10 @@ call fails (for example because the path doesn't exist). .. versionadded:: 3.10 + .. versionchanged:: 3.13 + Raises :exc:`UnsupportedOperation` if :func:`os.link` is not + available. In previous versions, :exc:`NotImplementedError` was raised. + .. method:: Path.touch(mode=0o666, exist_ok=True) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 6cf2bd2426370c..d1f13a50335b5b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -106,6 +106,10 @@ built on debug mode `. pathlib ------- +* Add :exc:`pathlib.UnsupportedOperation`, which is raised instead of + :exc:`NotImplementedError` when a path operation isn't supported. + (Contributed by Barney Gale in :gh:`89812`.) + * Add support for recursive wildcards in :meth:`pathlib.PurePath.match`. (Contributed by Barney Gale in :gh:`73435`.) diff --git a/Lib/pathlib.py b/Lib/pathlib.py index d8c597f1027f30..a36ffdd73d8af1 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -21,6 +21,7 @@ __all__ = [ + "UnsupportedOperation", "PurePath", "PurePosixPath", "PureWindowsPath", "Path", "PosixPath", "WindowsPath", ] @@ -207,6 +208,13 @@ def _select_unique(paths): # Public API # +class UnsupportedOperation(NotImplementedError): + """An exception that is raised when an unsupported operation is called on + a path object. + """ + pass + + class _PathParents(Sequence): """This object provides sequence-like access to the logical ancestors of a path. Don't try to construct it yourself.""" @@ -1241,7 +1249,7 @@ def owner(self): import pwd return pwd.getpwuid(self.stat().st_uid).pw_name except ImportError: - raise NotImplementedError("Path.owner() is unsupported on this system") + raise UnsupportedOperation("Path.owner() is unsupported on this system") def group(self): """ @@ -1252,14 +1260,14 @@ def group(self): import grp return grp.getgrgid(self.stat().st_gid).gr_name except ImportError: - raise NotImplementedError("Path.group() is unsupported on this system") + raise UnsupportedOperation("Path.group() is unsupported on this system") def readlink(self): """ Return the path to which the symbolic link points. """ if not hasattr(os, "readlink"): - raise NotImplementedError("os.readlink() not available on this system") + raise UnsupportedOperation("os.readlink() not available on this system") return self.with_segments(os.readlink(self)) def touch(self, mode=0o666, exist_ok=True): @@ -1363,7 +1371,7 @@ def symlink_to(self, target, target_is_directory=False): Note the order of arguments (link, target) is the reverse of os.symlink. """ if not hasattr(os, "symlink"): - raise NotImplementedError("os.symlink() not available on this system") + raise UnsupportedOperation("os.symlink() not available on this system") os.symlink(target, self, target_is_directory) def hardlink_to(self, target): @@ -1373,7 +1381,7 @@ def hardlink_to(self, target): Note the order of arguments (self, target) is the reverse of os.link's. """ if not hasattr(os, "link"): - raise NotImplementedError("os.link() not available on this system") + raise UnsupportedOperation("os.link() not available on this system") os.link(target, self) def expanduser(self): @@ -1400,7 +1408,7 @@ class PosixPath(Path, PurePosixPath): if os.name == 'nt': def __new__(cls, *args, **kwargs): - raise NotImplementedError( + raise UnsupportedOperation( f"cannot instantiate {cls.__name__!r} on your system") class WindowsPath(Path, PureWindowsPath): @@ -1412,5 +1420,5 @@ class WindowsPath(Path, PureWindowsPath): if os.name != 'nt': def __new__(cls, *args, **kwargs): - raise NotImplementedError( + raise UnsupportedOperation( f"cannot instantiate {cls.__name__!r} on your system") diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 02a0f25e0bd991..f9356909cb0982 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -24,6 +24,12 @@ grp = pwd = None +class UnsupportedOperationTest(unittest.TestCase): + def test_is_notimplemented(self): + self.assertTrue(issubclass(pathlib.UnsupportedOperation, NotImplementedError)) + self.assertTrue(isinstance(pathlib.UnsupportedOperation(), NotImplementedError)) + + # Make sure any symbolic links in the base test path are resolved. BASE = os.path.realpath(TESTFN) join = lambda *x: os.path.join(BASE, *x) @@ -1550,12 +1556,12 @@ class WindowsPathAsPureTest(PureWindowsPathTest): def test_owner(self): P = self.cls - with self.assertRaises(NotImplementedError): + with self.assertRaises(pathlib.UnsupportedOperation): P('c:/').owner() def test_group(self): P = self.cls - with self.assertRaises(NotImplementedError): + with self.assertRaises(pathlib.UnsupportedOperation): P('c:/').group() @@ -2055,6 +2061,13 @@ def test_readlink(self): with self.assertRaises(OSError): (P / 'fileA').readlink() + @unittest.skipIf(hasattr(os, "readlink"), "os.readlink() is present") + def test_readlink_unsupported(self): + P = self.cls(BASE) + p = P / 'fileA' + with self.assertRaises(pathlib.UnsupportedOperation): + q.readlink(p) + def _check_resolve(self, p, expected, strict=True): q = p.resolve(strict) self.assertEqual(q, expected) @@ -2343,7 +2356,7 @@ def test_unsupported_flavour(self): if self.cls._flavour is os.path: self.skipTest("path flavour is supported") else: - self.assertRaises(NotImplementedError, self.cls) + self.assertRaises(pathlib.UnsupportedOperation, self.cls) def _test_cwd(self, p): q = self.cls(os.getcwd()) @@ -2543,12 +2556,12 @@ def test_hardlink_to(self): self.assertTrue(link2.exists()) @unittest.skipIf(hasattr(os, "link"), "os.link() is present") - def test_link_to_not_implemented(self): + def test_hardlink_to_unsupported(self): P = self.cls(BASE) p = P / 'fileA' # linking to another path. q = P / 'dirA' / 'fileAA' - with self.assertRaises(NotImplementedError): + with self.assertRaises(pathlib.UnsupportedOperation): q.hardlink_to(p) def test_rename(self): @@ -2776,6 +2789,15 @@ def test_symlink_to(self): self.assertTrue(link.is_dir()) self.assertTrue(list(link.iterdir())) + @unittest.skipIf(hasattr(os, "symlink"), "os.symlink() is present") + def test_symlink_to_unsupported(self): + P = self.cls(BASE) + p = P / 'fileA' + # linking to another path. + q = P / 'dirA' / 'fileAA' + with self.assertRaises(pathlib.UnsupportedOperation): + q.symlink_to(p) + def test_is_junction(self): P = self.cls(BASE) diff --git a/Misc/NEWS.d/next/Library/2023-06-19-22-20-41.gh-issue-89812.z2l_e8.rst b/Misc/NEWS.d/next/Library/2023-06-19-22-20-41.gh-issue-89812.z2l_e8.rst new file mode 100644 index 00000000000000..f1ef11e26bc5fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-19-22-20-41.gh-issue-89812.z2l_e8.rst @@ -0,0 +1,2 @@ +Add :exc:`pathlib.UnsupportedOperation`, which is raised instead of +:exc:`NotImplementedError` when a path operation isn't supported. From 13237a2da846efef9ce9b93fd4bcfebd49933568 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 22 Jun 2023 16:56:40 +0100 Subject: [PATCH 111/446] gh-98931: Add custom error messages to invalid import/from with multiple targets (#105985) Co-authored-by: Alex Waygood --- Grammar/python.gram | 2 +- Lib/test/test_syntax.py | 16 + ...3-06-22-14-19-17.gh-issue-98931.PPgvSF.rst | 2 + Parser/parser.c | 1537 +++++++++-------- 4 files changed, 849 insertions(+), 708 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst diff --git a/Grammar/python.gram b/Grammar/python.gram index 6b2a46aff0dcf0..c1863aec67cc2b 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -1293,7 +1293,7 @@ invalid_group: | '(' a='**' expression ')' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") } invalid_import: - | a='import' dotted_name 'from' dotted_name { + | a='import' ','.dotted_name+ 'from' dotted_name { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") } invalid_import_from_targets: diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 477879db2fd493..f3d6cd7bad0eec 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -1621,6 +1621,22 @@ Traceback (most recent call last): SyntaxError: Did you mean to use 'from ... import ...' instead? +>>> import a, b,c from b +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a.y.z, b.y.z, c.y.z from b.y.z +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a,b,c from b as bar +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + +>>> import a.y.z, b.y.z, c.y.z from b.y.z as bar +Traceback (most recent call last): +SyntaxError: Did you mean to use 'from ... import ...' instead? + # Check that we dont raise the "trailing comma" error if there is more # input to the left of the valid part that we parsed. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst new file mode 100644 index 00000000000000..611660d6286263 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-14-19-17.gh-issue-98931.PPgvSF.rst @@ -0,0 +1,2 @@ +Ensure custom :exc:`SyntaxError` error messages are raised for invalid +imports with multiple targets. Patch by Pablo Galindo diff --git a/Parser/parser.c b/Parser/parser.c index 006ee297974a61..f2ea8f59b00567 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -532,14 +532,14 @@ static char *soft_keywords[] = { #define _gather_207_type 1451 #define _loop0_210_type 1452 #define _gather_209_type 1453 -#define _tmp_211_type 1454 -#define _loop0_212_type 1455 -#define _loop1_213_type 1456 -#define _tmp_214_type 1457 -#define _loop0_215_type 1458 -#define _loop1_216_type 1459 -#define _tmp_217_type 1460 -#define _tmp_218_type 1461 +#define _loop0_212_type 1454 +#define _gather_211_type 1455 +#define _tmp_213_type 1456 +#define _loop0_214_type 1457 +#define _loop1_215_type 1458 +#define _tmp_216_type 1459 +#define _loop0_217_type 1460 +#define _loop1_218_type 1461 #define _tmp_219_type 1462 #define _tmp_220_type 1463 #define _tmp_221_type 1464 @@ -548,10 +548,10 @@ static char *soft_keywords[] = { #define _tmp_224_type 1467 #define _tmp_225_type 1468 #define _tmp_226_type 1469 -#define _loop0_228_type 1470 -#define _gather_227_type 1471 -#define _tmp_229_type 1472 -#define _tmp_230_type 1473 +#define _tmp_227_type 1470 +#define _tmp_228_type 1471 +#define _loop0_230_type 1472 +#define _gather_229_type 1473 #define _tmp_231_type 1474 #define _tmp_232_type 1475 #define _tmp_233_type 1476 @@ -563,9 +563,9 @@ static char *soft_keywords[] = { #define _tmp_239_type 1482 #define _tmp_240_type 1483 #define _tmp_241_type 1484 -#define _loop0_242_type 1485 +#define _tmp_242_type 1485 #define _tmp_243_type 1486 -#define _tmp_244_type 1487 +#define _loop0_244_type 1487 #define _tmp_245_type 1488 #define _tmp_246_type 1489 #define _tmp_247_type 1490 @@ -596,6 +596,8 @@ static char *soft_keywords[] = { #define _tmp_272_type 1515 #define _tmp_273_type 1516 #define _tmp_274_type 1517 +#define _tmp_275_type 1518 +#define _tmp_276_type 1519 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -1051,14 +1053,14 @@ static asdl_seq *_loop0_208_rule(Parser *p); static asdl_seq *_gather_207_rule(Parser *p); static asdl_seq *_loop0_210_rule(Parser *p); static asdl_seq *_gather_209_rule(Parser *p); -static void *_tmp_211_rule(Parser *p); static asdl_seq *_loop0_212_rule(Parser *p); -static asdl_seq *_loop1_213_rule(Parser *p); -static void *_tmp_214_rule(Parser *p); -static asdl_seq *_loop0_215_rule(Parser *p); -static asdl_seq *_loop1_216_rule(Parser *p); -static void *_tmp_217_rule(Parser *p); -static void *_tmp_218_rule(Parser *p); +static asdl_seq *_gather_211_rule(Parser *p); +static void *_tmp_213_rule(Parser *p); +static asdl_seq *_loop0_214_rule(Parser *p); +static asdl_seq *_loop1_215_rule(Parser *p); +static void *_tmp_216_rule(Parser *p); +static asdl_seq *_loop0_217_rule(Parser *p); +static asdl_seq *_loop1_218_rule(Parser *p); static void *_tmp_219_rule(Parser *p); static void *_tmp_220_rule(Parser *p); static void *_tmp_221_rule(Parser *p); @@ -1067,10 +1069,10 @@ static void *_tmp_223_rule(Parser *p); static void *_tmp_224_rule(Parser *p); static void *_tmp_225_rule(Parser *p); static void *_tmp_226_rule(Parser *p); -static asdl_seq *_loop0_228_rule(Parser *p); -static asdl_seq *_gather_227_rule(Parser *p); -static void *_tmp_229_rule(Parser *p); -static void *_tmp_230_rule(Parser *p); +static void *_tmp_227_rule(Parser *p); +static void *_tmp_228_rule(Parser *p); +static asdl_seq *_loop0_230_rule(Parser *p); +static asdl_seq *_gather_229_rule(Parser *p); static void *_tmp_231_rule(Parser *p); static void *_tmp_232_rule(Parser *p); static void *_tmp_233_rule(Parser *p); @@ -1082,9 +1084,9 @@ static void *_tmp_238_rule(Parser *p); static void *_tmp_239_rule(Parser *p); static void *_tmp_240_rule(Parser *p); static void *_tmp_241_rule(Parser *p); -static asdl_seq *_loop0_242_rule(Parser *p); +static void *_tmp_242_rule(Parser *p); static void *_tmp_243_rule(Parser *p); -static void *_tmp_244_rule(Parser *p); +static asdl_seq *_loop0_244_rule(Parser *p); static void *_tmp_245_rule(Parser *p); static void *_tmp_246_rule(Parser *p); static void *_tmp_247_rule(Parser *p); @@ -1115,6 +1117,8 @@ static void *_tmp_271_rule(Parser *p); static void *_tmp_272_rule(Parser *p); static void *_tmp_273_rule(Parser *p); static void *_tmp_274_rule(Parser *p); +static void *_tmp_275_rule(Parser *p); +static void *_tmp_276_rule(Parser *p); // file: statements? $ @@ -22648,7 +22652,7 @@ invalid_group_rule(Parser *p) return _res; } -// invalid_import: 'import' dotted_name 'from' dotted_name +// invalid_import: 'import' ','.dotted_name+ 'from' dotted_name static void * invalid_import_rule(Parser *p) { @@ -22662,27 +22666,27 @@ invalid_import_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'import' dotted_name 'from' dotted_name + { // 'import' ','.dotted_name+ 'from' dotted_name if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); + asdl_seq * _gather_203_var; Token * _keyword; Token * a; expr_ty dotted_name_var; - expr_ty dotted_name_var_1; if ( (a = _PyPegen_expect_token(p, 607)) // token='import' && - (dotted_name_var = dotted_name_rule(p)) // dotted_name + (_gather_203_var = _gather_203_rule(p)) // ','.dotted_name+ && (_keyword = _PyPegen_expect_token(p, 608)) // token='from' && - (dotted_name_var_1 = dotted_name_rule(p)) // dotted_name + (dotted_name_var = dotted_name_rule(p)) // dotted_name ) { - D(fprintf(stderr, "%*c+ invalid_import[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + D(fprintf(stderr, "%*c+ invalid_import[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( a , "Did you mean to use 'from ... import ...' instead?" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -22693,7 +22697,7 @@ invalid_import_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_import[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import' dotted_name 'from' dotted_name")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); } _res = NULL; done: @@ -22773,7 +22777,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_203_var; + asdl_seq * _gather_205_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22783,7 +22787,7 @@ invalid_with_stmt_rule(Parser *p) && (_keyword = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_203_var = _gather_203_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_205_var = _gather_205_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -22807,7 +22811,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_205_var; + asdl_seq * _gather_207_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -22823,7 +22827,7 @@ invalid_with_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_205_var = _gather_205_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_207_var = _gather_207_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -22873,7 +22877,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_207_var; + asdl_seq * _gather_209_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -22884,7 +22888,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (a = _PyPegen_expect_token(p, 615)) // token='with' && - (_gather_207_var = _gather_207_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_209_var = _gather_209_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -22912,7 +22916,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_209_var; + asdl_seq * _gather_211_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -22929,7 +22933,7 @@ invalid_with_stmt_indent_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_209_var = _gather_209_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_211_var = _gather_211_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -23027,7 +23031,7 @@ invalid_try_stmt_rule(Parser *p) && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_211_rule, p) + _PyPegen_lookahead(0, _tmp_213_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -23052,8 +23056,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_212_var; - asdl_seq * _loop1_213_var; + asdl_seq * _loop0_214_var; + asdl_seq * _loop1_215_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -23064,9 +23068,9 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_212_var = _loop0_212_rule(p)) // block* + (_loop0_214_var = _loop0_214_rule(p)) // block* && - (_loop1_213_var = _loop1_213_rule(p)) // except_block+ + (_loop1_215_var = _loop1_215_rule(p)) // except_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && @@ -23074,7 +23078,7 @@ invalid_try_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23101,8 +23105,8 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_215_var; - asdl_seq * _loop1_216_var; + asdl_seq * _loop0_217_var; + asdl_seq * _loop1_218_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; @@ -23111,13 +23115,13 @@ invalid_try_stmt_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_215_var = _loop0_215_rule(p)) // block* + (_loop0_217_var = _loop0_217_rule(p)) // block* && - (_loop1_216_var = _loop1_216_rule(p)) // except_star_block+ + (_loop1_218_var = _loop1_218_rule(p)) // except_star_block+ && (a = _PyPegen_expect_token(p, 637)) // token='except' && - (_opt_var = _tmp_217_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_219_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23185,7 +23189,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_opt_var_1 = _tmp_218_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_220_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -23223,7 +23227,7 @@ invalid_except_stmt_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var_1 = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -23275,14 +23279,14 @@ invalid_except_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_220_var; + void *_tmp_222_var; Token * a; if ( (a = _PyPegen_expect_token(p, 637)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_220_var = _tmp_220_rule(p)) // NEWLINE | ':' + (_tmp_222_var = _tmp_222_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -23389,7 +23393,7 @@ invalid_except_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_223_rule(p), !p->error_indicator) // ['as' NAME] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23484,7 +23488,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) && (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_224_rule(p), !p->error_indicator) // ['as' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -23853,7 +23857,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_223_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_225_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -24347,7 +24351,7 @@ invalid_def_raw_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' && - (_opt_var_2 = _tmp_224_rule(p), !p->error_indicator) // ['->' expression] + (_opt_var_2 = _tmp_226_rule(p), !p->error_indicator) // ['->' expression] && (_literal_2 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24407,7 +24411,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_225_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_227_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24442,7 +24446,7 @@ invalid_class_def_raw_rule(Parser *p) && (name_var = _PyPegen_name_token(p)) // NAME && - (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')'] + (_opt_var = _tmp_228_rule(p), !p->error_indicator) // ['(' arguments? ')'] && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24493,11 +24497,11 @@ invalid_double_starred_kvpairs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_227_var; + asdl_seq * _gather_229_var; Token * _literal; void *invalid_kvpair_var; if ( - (_gather_227_var = _gather_227_rule(p)) // ','.double_starred_kvpair+ + (_gather_229_var = _gather_229_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -24505,7 +24509,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_227_var, _literal, invalid_kvpair_var); + _res = _PyPegen_dummy_name(p, _gather_229_var, _literal, invalid_kvpair_var); goto done; } p->mark = _mark; @@ -24558,7 +24562,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_229_rule, p) + _PyPegen_lookahead(1, _tmp_231_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24669,7 +24673,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_230_rule, p) + _PyPegen_lookahead(1, _tmp_232_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -24887,7 +24891,7 @@ invalid_replacement_field_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - _PyPegen_lookahead(0, _tmp_231_rule, p) + _PyPegen_lookahead(0, _tmp_233_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)")); @@ -24910,13 +24914,13 @@ invalid_replacement_field_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); Token * _literal; - void *_tmp_232_var; + void *_tmp_234_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions + (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions && - _PyPegen_lookahead(0, _tmp_233_rule, p) + _PyPegen_lookahead(0, _tmp_235_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')")); @@ -24940,15 +24944,15 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); Token * _literal; Token * _literal_1; - void *_tmp_234_var; + void *_tmp_236_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions + (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_235_rule, p) + _PyPegen_lookahead(0, _tmp_237_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')")); @@ -24973,12 +24977,12 @@ invalid_replacement_field_rule(Parser *p) Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_236_var; + void *_tmp_238_var; void *invalid_conversion_character_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions + (_tmp_238_var = _tmp_238_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && @@ -24986,7 +24990,7 @@ invalid_replacement_field_rule(Parser *p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_236_var, _opt_var, invalid_conversion_character_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_238_var, _opt_var, invalid_conversion_character_var); goto done; } p->mark = _mark; @@ -25004,17 +25008,17 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_237_var; + void *_tmp_239_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_237_var = _tmp_237_rule(p)) // yield_expr | star_expressions + (_tmp_239_var = _tmp_239_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_238_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_240_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_239_rule, p) + _PyPegen_lookahead(0, _tmp_241_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')")); @@ -25038,24 +25042,24 @@ invalid_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_242_var; + asdl_seq * _loop0_244_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_240_var; + void *_tmp_242_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_240_var = _tmp_240_rule(p)) // yield_expr | star_expressions + (_tmp_242_var = _tmp_242_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_241_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_243_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_242_var = _loop0_242_rule(p)) // fstring_format_spec* + (_loop0_244_var = _loop0_244_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25084,15 +25088,15 @@ invalid_replacement_field_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; UNUSED(_opt_var_1); // Silence compiler warnings - void *_tmp_243_var; + void *_tmp_245_var; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_tmp_243_var = _tmp_243_rule(p)) // yield_expr | star_expressions + (_tmp_245_var = _tmp_245_rule(p)) // yield_expr | star_expressions && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_244_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_246_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -25140,7 +25144,7 @@ invalid_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_245_rule, p) + _PyPegen_lookahead(1, _tmp_247_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -26085,12 +26089,12 @@ _loop1_15_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_246_var; + void *_tmp_248_var; while ( - (_tmp_246_var = _tmp_246_rule(p)) // star_targets '=' + (_tmp_248_var = _tmp_248_rule(p)) // star_targets '=' ) { - _res = _tmp_246_var; + _res = _tmp_248_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26664,12 +26668,12 @@ _loop0_25_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_247_var; + void *_tmp_249_var; while ( - (_tmp_247_var = _tmp_247_rule(p)) // '.' | '...' + (_tmp_249_var = _tmp_249_rule(p)) // '.' | '...' ) { - _res = _tmp_247_var; + _res = _tmp_249_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -26732,12 +26736,12 @@ _loop1_26_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_248_var; + void *_tmp_250_var; while ( - (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...' + (_tmp_250_var = _tmp_250_rule(p)) // '.' | '...' ) { - _res = _tmp_248_var; + _res = _tmp_250_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -27137,12 +27141,12 @@ _loop1_33_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_249_var; + void *_tmp_251_var; while ( - (_tmp_249_var = _tmp_249_rule(p)) // '@' named_expression NEWLINE + (_tmp_251_var = _tmp_251_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_249_var; + _res = _tmp_251_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30317,12 +30321,12 @@ _loop1_83_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)")); - void *_tmp_250_var; + void *_tmp_252_var; while ( - (_tmp_250_var = _tmp_250_rule(p)) // ',' expression + (_tmp_252_var = _tmp_252_rule(p)) // ',' expression ) { - _res = _tmp_250_var; + _res = _tmp_252_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30390,12 +30394,12 @@ _loop1_84_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_251_var; + void *_tmp_253_var; while ( - (_tmp_251_var = _tmp_251_rule(p)) // ',' star_expression + (_tmp_253_var = _tmp_253_rule(p)) // ',' star_expression ) { - _res = _tmp_251_var; + _res = _tmp_253_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30582,12 +30586,12 @@ _loop1_87_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_252_var; + void *_tmp_254_var; while ( - (_tmp_252_var = _tmp_252_rule(p)) // 'or' conjunction + (_tmp_254_var = _tmp_254_rule(p)) // 'or' conjunction ) { - _res = _tmp_252_var; + _res = _tmp_254_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30655,12 +30659,12 @@ _loop1_88_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_253_var; + void *_tmp_255_var; while ( - (_tmp_253_var = _tmp_253_rule(p)) // 'and' inversion + (_tmp_255_var = _tmp_255_rule(p)) // 'and' inversion ) { - _res = _tmp_253_var; + _res = _tmp_255_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -30850,7 +30854,7 @@ _loop0_92_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_254_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression ) { _res = elem; @@ -30916,7 +30920,7 @@ _gather_91_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_254_rule(p)) // slice | starred_expression + (elem = _tmp_256_rule(p)) // slice | starred_expression && (seq = _loop0_92_rule(p)) // _loop0_92 ) @@ -32471,12 +32475,12 @@ _loop1_115_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_255_var; + void *_tmp_257_var; while ( - (_tmp_255_var = _tmp_255_rule(p)) // fstring | string + (_tmp_257_var = _tmp_257_rule(p)) // fstring | string ) { - _res = _tmp_255_var; + _res = _tmp_257_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32786,12 +32790,12 @@ _loop0_120_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_256_var; + void *_tmp_258_var; while ( - (_tmp_256_var = _tmp_256_rule(p)) // 'if' disjunction + (_tmp_258_var = _tmp_258_rule(p)) // 'if' disjunction ) { - _res = _tmp_256_var; + _res = _tmp_258_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32854,12 +32858,12 @@ _loop0_121_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_257_var; + void *_tmp_259_var; while ( - (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction + (_tmp_259_var = _tmp_259_rule(p)) // 'if' disjunction ) { - _res = _tmp_257_var; + _res = _tmp_259_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32987,7 +32991,7 @@ _loop0_124_rule(Parser *p) while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -33054,7 +33058,7 @@ _gather_123_rule(Parser *p) void *elem; asdl_seq * seq; if ( - (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_260_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && (seq = _loop0_124_rule(p)) // _loop0_124 ) @@ -33625,12 +33629,12 @@ _loop0_134_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_259_var; + void *_tmp_261_var; while ( - (_tmp_259_var = _tmp_259_rule(p)) // ',' star_target + (_tmp_261_var = _tmp_261_rule(p)) // ',' star_target ) { - _res = _tmp_259_var; + _res = _tmp_261_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33812,12 +33816,12 @@ _loop1_137_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_260_var; + void *_tmp_262_var; while ( - (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target + (_tmp_262_var = _tmp_262_rule(p)) // ',' star_target ) { - _res = _tmp_260_var; + _res = _tmp_262_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35338,12 +35342,12 @@ _loop0_162_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_261_var; + void *_tmp_263_var; while ( - (_tmp_261_var = _tmp_261_rule(p)) // star_targets '=' + (_tmp_263_var = _tmp_263_rule(p)) // star_targets '=' ) { - _res = _tmp_261_var; + _res = _tmp_263_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35406,12 +35410,12 @@ _loop0_163_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_262_var; + void *_tmp_264_var; while ( - (_tmp_262_var = _tmp_262_rule(p)) // star_targets '=' + (_tmp_264_var = _tmp_264_rule(p)) // star_targets '=' ) { - _res = _tmp_262_var; + _res = _tmp_264_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -36454,15 +36458,15 @@ _tmp_179_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_263_var; + void *_tmp_265_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_263_var = _tmp_263_rule(p)) // ')' | '**' + (_tmp_265_var = _tmp_265_rule(p)) // ')' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_263_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_265_var); goto done; } p->mark = _mark; @@ -37628,15 +37632,15 @@ _tmp_197_rule(Parser *p) } D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_264_var; + void *_tmp_266_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_264_var = _tmp_264_rule(p)) // ':' | '**' + (_tmp_266_var = _tmp_266_rule(p)) // ':' | '**' ) { D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var); + _res = _PyPegen_dummy_name(p, _literal, _tmp_266_var); goto done; } p->mark = _mark; @@ -37987,7 +37991,7 @@ _tmp_202_rule(Parser *p) return _res; } -// _loop0_204: ',' (expression ['as' star_target]) +// _loop0_204: ',' dotted_name static asdl_seq * _loop0_204_rule(Parser *p) { @@ -38010,18 +38014,18 @@ _loop0_204_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expression ['as' star_target]) + { // ',' dotted_name if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; - void *elem; + expr_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = dotted_name_rule(p)) // dotted_name ) { _res = elem; @@ -38048,7 +38052,7 @@ _loop0_204_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38064,7 +38068,7 @@ _loop0_204_rule(Parser *p) return _seq; } -// _gather_203: (expression ['as' star_target]) _loop0_204 +// _gather_203: dotted_name _loop0_204 static asdl_seq * _gather_203_rule(Parser *p) { @@ -38078,27 +38082,27 @@ _gather_203_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_204 + { // dotted_name _loop0_204 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); - void *elem; + D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); + expr_ty elem; asdl_seq * seq; if ( - (elem = _tmp_265_rule(p)) // expression ['as' star_target] + (elem = dotted_name_rule(p)) // dotted_name && (seq = _loop0_204_rule(p)) // _loop0_204 ) { - D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); + D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_204")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_204")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_204")); } _res = NULL; done: @@ -38106,7 +38110,7 @@ _gather_203_rule(Parser *p) return _res; } -// _loop0_206: ',' (expressions ['as' star_target]) +// _loop0_206: ',' (expression ['as' star_target]) static asdl_seq * _loop0_206_rule(Parser *p) { @@ -38129,18 +38133,18 @@ _loop0_206_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expressions ['as' star_target]) + { // ',' (expression ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -38167,7 +38171,7 @@ _loop0_206_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38183,7 +38187,7 @@ _loop0_206_rule(Parser *p) return _seq; } -// _gather_205: (expressions ['as' star_target]) _loop0_206 +// _gather_205: (expression ['as' star_target]) _loop0_206 static asdl_seq * _gather_205_rule(Parser *p) { @@ -38197,27 +38201,27 @@ _gather_205_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_206 + { // (expression ['as' star_target]) _loop0_206 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_266_rule(p)) // expressions ['as' star_target] + (elem = _tmp_267_rule(p)) // expression ['as' star_target] && (seq = _loop0_206_rule(p)) // _loop0_206 ) { - D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_206")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_206")); } _res = NULL; done: @@ -38225,7 +38229,7 @@ _gather_205_rule(Parser *p) return _res; } -// _loop0_208: ',' (expression ['as' star_target]) +// _loop0_208: ',' (expressions ['as' star_target]) static asdl_seq * _loop0_208_rule(Parser *p) { @@ -38248,18 +38252,18 @@ _loop0_208_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expression ['as' star_target]) + { // ',' (expressions ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -38286,7 +38290,7 @@ _loop0_208_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38302,7 +38306,7 @@ _loop0_208_rule(Parser *p) return _seq; } -// _gather_207: (expression ['as' star_target]) _loop0_208 +// _gather_207: (expressions ['as' star_target]) _loop0_208 static asdl_seq * _gather_207_rule(Parser *p) { @@ -38316,27 +38320,27 @@ _gather_207_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_208 + { // (expressions ['as' star_target]) _loop0_208 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_267_rule(p)) // expression ['as' star_target] + (elem = _tmp_268_rule(p)) // expressions ['as' star_target] && (seq = _loop0_208_rule(p)) // _loop0_208 ) { - D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_208")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_208")); } _res = NULL; done: @@ -38344,7 +38348,7 @@ _gather_207_rule(Parser *p) return _res; } -// _loop0_210: ',' (expressions ['as' star_target]) +// _loop0_210: ',' (expression ['as' star_target]) static asdl_seq * _loop0_210_rule(Parser *p) { @@ -38367,18 +38371,18 @@ _loop0_210_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (expressions ['as' star_target]) + { // ',' (expression ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -38405,7 +38409,7 @@ _loop0_210_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38421,7 +38425,7 @@ _loop0_210_rule(Parser *p) return _seq; } -// _gather_209: (expressions ['as' star_target]) _loop0_210 +// _gather_209: (expression ['as' star_target]) _loop0_210 static asdl_seq * _gather_209_rule(Parser *p) { @@ -38435,27 +38439,27 @@ _gather_209_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_210 + { // (expression ['as' star_target]) _loop0_210 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_268_rule(p)) // expressions ['as' star_target] + (elem = _tmp_269_rule(p)) // expression ['as' star_target] && (seq = _loop0_210_rule(p)) // _loop0_210 ) { - D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_210")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_210")); } _res = NULL; done: @@ -38463,65 +38467,7 @@ _gather_209_rule(Parser *p) return _res; } -// _tmp_211: 'except' | 'finally' -static void * -_tmp_211_rule(Parser *p) -{ - if (p->level++ == MAXSTACK) { - p->error_indicator = 1; - PyErr_NoMemory(); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // 'except' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); - Token * _keyword; - if ( - (_keyword = _PyPegen_expect_token(p, 637)) // token='except' - ) - { - D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); - _res = _keyword; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); - } - { // 'finally' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); - Token * _keyword; - if ( - (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' - ) - { - D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); - _res = _keyword; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_212: block +// _loop0_212: ',' (expressions ['as' star_target]) static asdl_seq * _loop0_212_rule(Parser *p) { @@ -38544,18 +38490,27 @@ _loop0_212_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // block + { // ',' (expressions ['as' star_target]) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); - asdl_stmt_seq* block_var; + D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + Token * _literal; + void *elem; while ( - (block_var = block_rule(p)) // block + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = _tmp_270_rule(p)) // expressions ['as' star_target] ) { - _res = block_var; + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -38573,7 +38528,7 @@ _loop0_212_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_212[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -38589,9 +38544,9 @@ _loop0_212_rule(Parser *p) return _seq; } -// _loop1_213: except_block +// _gather_211: (expressions ['as' star_target]) _loop0_212 static asdl_seq * -_loop1_213_rule(Parser *p) +_gather_211_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38601,70 +38556,39 @@ _loop1_213_rule(Parser *p) p->level--; return NULL; } - void *_res = NULL; + asdl_seq * _res = NULL; int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // except_block + { // (expressions ['as' star_target]) _loop0_212 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); - excepthandler_ty except_block_var; - while ( - (except_block_var = except_block_rule(p)) // except_block + D(fprintf(stderr, "%*c> _gather_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + void *elem; + asdl_seq * seq; + if ( + (elem = _tmp_270_rule(p)) // expressions ['as' star_target] + && + (seq = _loop0_212_rule(p)) // _loop0_212 ) { - _res = except_block_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; + D(fprintf(stderr, "%*c+ _gather_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_213[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; + D(fprintf(stderr, "%*c%s _gather_211[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_212")); } - for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); + _res = NULL; + done: p->level--; - return _seq; + return _res; } -// _tmp_214: 'as' NAME +// _tmp_213: 'except' | 'finally' static void * -_tmp_214_rule(Parser *p) +_tmp_213_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38676,27 +38600,43 @@ _tmp_214_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // 'as' NAME + { // 'except' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; - expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 640)) // token='as' - && - (name_var = _PyPegen_name_token(p)) // NAME + (_keyword = _PyPegen_expect_token(p, 637)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_214[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); - _res = _PyPegen_dummy_name(p, _keyword, name_var); + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_214[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); + } + { // 'finally' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + Token * _keyword; + if ( + (_keyword = _PyPegen_expect_token(p, 633)) // token='finally' + ) + { + D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + _res = _keyword; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; done: @@ -38704,9 +38644,9 @@ _tmp_214_rule(Parser *p) return _res; } -// _loop0_215: block +// _loop0_214: block static asdl_seq * -_loop0_215_rule(Parser *p) +_loop0_214_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38732,7 +38672,7 @@ _loop0_215_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -38755,7 +38695,7 @@ _loop0_215_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_215[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_214[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38772,9 +38712,9 @@ _loop0_215_rule(Parser *p) return _seq; } -// _loop1_216: except_star_block +// _loop1_215: except_block static asdl_seq * -_loop1_216_rule(Parser *p) +_loop1_215_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38795,18 +38735,18 @@ _loop1_216_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // except_star_block + { // except_block if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); - excepthandler_ty except_star_block_var; + D(fprintf(stderr, "%*c> _loop1_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block")); + excepthandler_ty except_block_var; while ( - (except_star_block_var = except_star_block_rule(p)) // except_star_block + (except_block_var = except_block_rule(p)) // except_block ) { - _res = except_star_block_var; + _res = except_block_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -38823,8 +38763,8 @@ _loop1_216_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_216[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); + D(fprintf(stderr, "%*c%s _loop1_215[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block")); } if (_n == 0 || p->error_indicator) { PyMem_Free(_children); @@ -38845,9 +38785,192 @@ _loop1_216_rule(Parser *p) return _seq; } -// _tmp_217: expression ['as' NAME] +// _tmp_216: 'as' NAME static void * -_tmp_217_rule(Parser *p) +_tmp_216_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'as' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + Token * _keyword; + expr_ty name_var; + if ( + (_keyword = _PyPegen_expect_token(p, 640)) // token='as' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + _res = _PyPegen_dummy_name(p, _keyword, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_217: block +static asdl_seq * +_loop0_217_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // block + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + asdl_stmt_seq* block_var; + while ( + (block_var = block_rule(p)) // block + ) + { + _res = block_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_217[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_218: except_star_block +static asdl_seq * +_loop1_218_rule(Parser *p) +{ + if (p->level++ == MAXSTACK) { + p->error_indicator = 1; + PyErr_NoMemory(); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // except_star_block + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block")); + excepthandler_ty except_star_block_var; + while ( + (except_star_block_var = except_star_block_rule(p)) // except_star_block + ) + { + _res = except_star_block_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_218[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _tmp_219: expression ['as' NAME] +static void * +_tmp_219_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38864,22 +38987,22 @@ _tmp_217_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' NAME] + (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -38888,9 +39011,9 @@ _tmp_217_rule(Parser *p) return _res; } -// _tmp_218: 'as' NAME +// _tmp_220: 'as' NAME static void * -_tmp_218_rule(Parser *p) +_tmp_220_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38907,7 +39030,7 @@ _tmp_218_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38916,12 +39039,12 @@ _tmp_218_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38930,9 +39053,9 @@ _tmp_218_rule(Parser *p) return _res; } -// _tmp_219: 'as' NAME +// _tmp_221: 'as' NAME static void * -_tmp_219_rule(Parser *p) +_tmp_221_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38949,7 +39072,7 @@ _tmp_219_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -38958,12 +39081,12 @@ _tmp_219_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -38972,9 +39095,9 @@ _tmp_219_rule(Parser *p) return _res; } -// _tmp_220: NEWLINE | ':' +// _tmp_222: NEWLINE | ':' static void * -_tmp_220_rule(Parser *p) +_tmp_222_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -38991,18 +39114,18 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -39010,18 +39133,18 @@ _tmp_220_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -39030,9 +39153,9 @@ _tmp_220_rule(Parser *p) return _res; } -// _tmp_221: 'as' NAME +// _tmp_223: 'as' NAME static void * -_tmp_221_rule(Parser *p) +_tmp_223_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39049,7 +39172,7 @@ _tmp_221_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -39058,12 +39181,12 @@ _tmp_221_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -39072,9 +39195,9 @@ _tmp_221_rule(Parser *p) return _res; } -// _tmp_222: 'as' NAME +// _tmp_224: 'as' NAME static void * -_tmp_222_rule(Parser *p) +_tmp_224_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39091,7 +39214,7 @@ _tmp_222_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -39100,12 +39223,12 @@ _tmp_222_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -39114,9 +39237,9 @@ _tmp_222_rule(Parser *p) return _res; } -// _tmp_223: positional_patterns ',' +// _tmp_225: positional_patterns ',' static void * -_tmp_223_rule(Parser *p) +_tmp_225_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39133,7 +39256,7 @@ _tmp_223_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -39142,12 +39265,12 @@ _tmp_223_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -39156,9 +39279,9 @@ _tmp_223_rule(Parser *p) return _res; } -// _tmp_224: '->' expression +// _tmp_226: '->' expression static void * -_tmp_224_rule(Parser *p) +_tmp_226_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39175,7 +39298,7 @@ _tmp_224_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression")); Token * _literal; expr_ty expression_var; if ( @@ -39184,12 +39307,12 @@ _tmp_224_rule(Parser *p) (expression_var = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); + D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression")); _res = _PyPegen_dummy_name(p, _literal, expression_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression")); } _res = NULL; @@ -39198,9 +39321,9 @@ _tmp_224_rule(Parser *p) return _res; } -// _tmp_225: '(' arguments? ')' +// _tmp_227: '(' arguments? ')' static void * -_tmp_225_rule(Parser *p) +_tmp_227_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39217,7 +39340,7 @@ _tmp_225_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -39230,12 +39353,12 @@ _tmp_225_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -39244,9 +39367,9 @@ _tmp_225_rule(Parser *p) return _res; } -// _tmp_226: '(' arguments? ')' +// _tmp_228: '(' arguments? ')' static void * -_tmp_226_rule(Parser *p) +_tmp_228_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39263,7 +39386,7 @@ _tmp_226_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); Token * _literal; Token * _literal_1; void *_opt_var; @@ -39276,12 +39399,12 @@ _tmp_226_rule(Parser *p) (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); + D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'")); _res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'")); } _res = NULL; @@ -39290,9 +39413,9 @@ _tmp_226_rule(Parser *p) return _res; } -// _loop0_228: ',' double_starred_kvpair +// _loop0_230: ',' double_starred_kvpair static asdl_seq * -_loop0_228_rule(Parser *p) +_loop0_230_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39318,7 +39441,7 @@ _loop0_228_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -39350,7 +39473,7 @@ _loop0_228_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_228[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_230[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -39367,9 +39490,9 @@ _loop0_228_rule(Parser *p) return _seq; } -// _gather_227: double_starred_kvpair _loop0_228 +// _gather_229: double_starred_kvpair _loop0_230 static asdl_seq * -_gather_227_rule(Parser *p) +_gather_229_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39381,27 +39504,27 @@ _gather_227_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_228 + { // double_starred_kvpair _loop0_230 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c> _gather_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_228_rule(p)) // _loop0_228 + (seq = _loop0_230_rule(p)) // _loop0_230 ) { - D(fprintf(stderr, "%*c+ _gather_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c+ _gather_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_230")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_227[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_228")); + D(fprintf(stderr, "%*c%s _gather_229[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_230")); } _res = NULL; done: @@ -39409,9 +39532,9 @@ _gather_227_rule(Parser *p) return _res; } -// _tmp_229: '}' | ',' +// _tmp_231: '}' | ',' static void * -_tmp_229_rule(Parser *p) +_tmp_231_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39428,18 +39551,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39447,18 +39570,18 @@ _tmp_229_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39467,9 +39590,9 @@ _tmp_229_rule(Parser *p) return _res; } -// _tmp_230: '}' | ',' +// _tmp_232: '}' | ',' static void * -_tmp_230_rule(Parser *p) +_tmp_232_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39486,18 +39609,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } { // ',' @@ -39505,18 +39628,18 @@ _tmp_230_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -39525,9 +39648,9 @@ _tmp_230_rule(Parser *p) return _res; } -// _tmp_231: yield_expr | star_expressions +// _tmp_233: yield_expr | star_expressions static void * -_tmp_231_rule(Parser *p) +_tmp_233_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39544,18 +39667,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39563,18 +39686,18 @@ _tmp_231_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39583,9 +39706,9 @@ _tmp_231_rule(Parser *p) return _res; } -// _tmp_232: yield_expr | star_expressions +// _tmp_234: yield_expr | star_expressions static void * -_tmp_232_rule(Parser *p) +_tmp_234_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39602,18 +39725,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39621,18 +39744,18 @@ _tmp_232_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39641,9 +39764,9 @@ _tmp_232_rule(Parser *p) return _res; } -// _tmp_233: '=' | '!' | ':' | '}' +// _tmp_235: '=' | '!' | ':' | '}' static void * -_tmp_233_rule(Parser *p) +_tmp_235_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39660,18 +39783,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // '!' @@ -39679,18 +39802,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39698,18 +39821,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39717,18 +39840,18 @@ _tmp_233_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39737,9 +39860,9 @@ _tmp_233_rule(Parser *p) return _res; } -// _tmp_234: yield_expr | star_expressions +// _tmp_236: yield_expr | star_expressions static void * -_tmp_234_rule(Parser *p) +_tmp_236_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39756,18 +39879,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39775,18 +39898,18 @@ _tmp_234_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39795,9 +39918,9 @@ _tmp_234_rule(Parser *p) return _res; } -// _tmp_235: '!' | ':' | '}' +// _tmp_237: '!' | ':' | '}' static void * -_tmp_235_rule(Parser *p) +_tmp_237_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39814,18 +39937,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); } { // ':' @@ -39833,18 +39956,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -39852,18 +39975,18 @@ _tmp_235_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -39872,9 +39995,9 @@ _tmp_235_rule(Parser *p) return _res; } -// _tmp_236: yield_expr | star_expressions +// _tmp_238: yield_expr | star_expressions static void * -_tmp_236_rule(Parser *p) +_tmp_238_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39891,18 +40014,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39910,18 +40033,18 @@ _tmp_236_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39930,9 +40053,9 @@ _tmp_236_rule(Parser *p) return _res; } -// _tmp_237: yield_expr | star_expressions +// _tmp_239: yield_expr | star_expressions static void * -_tmp_237_rule(Parser *p) +_tmp_239_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -39949,18 +40072,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -39968,18 +40091,18 @@ _tmp_237_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -39988,9 +40111,9 @@ _tmp_237_rule(Parser *p) return _res; } -// _tmp_238: '!' NAME +// _tmp_240: '!' NAME static void * -_tmp_238_rule(Parser *p) +_tmp_240_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40007,7 +40130,7 @@ _tmp_238_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40016,12 +40139,12 @@ _tmp_238_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40030,9 +40153,9 @@ _tmp_238_rule(Parser *p) return _res; } -// _tmp_239: ':' | '}' +// _tmp_241: ':' | '}' static void * -_tmp_239_rule(Parser *p) +_tmp_241_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40049,18 +40172,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -40068,18 +40191,18 @@ _tmp_239_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -40088,9 +40211,9 @@ _tmp_239_rule(Parser *p) return _res; } -// _tmp_240: yield_expr | star_expressions +// _tmp_242: yield_expr | star_expressions static void * -_tmp_240_rule(Parser *p) +_tmp_242_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40107,18 +40230,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -40126,18 +40249,18 @@ _tmp_240_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -40146,9 +40269,9 @@ _tmp_240_rule(Parser *p) return _res; } -// _tmp_241: '!' NAME +// _tmp_243: '!' NAME static void * -_tmp_241_rule(Parser *p) +_tmp_243_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40165,7 +40288,7 @@ _tmp_241_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40174,12 +40297,12 @@ _tmp_241_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40188,9 +40311,9 @@ _tmp_241_rule(Parser *p) return _res; } -// _loop0_242: fstring_format_spec +// _loop0_244: fstring_format_spec static asdl_seq * -_loop0_242_rule(Parser *p) +_loop0_244_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40216,7 +40339,7 @@ _loop0_242_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -40239,7 +40362,7 @@ _loop0_242_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_242[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_244[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -40256,9 +40379,9 @@ _loop0_242_rule(Parser *p) return _seq; } -// _tmp_243: yield_expr | star_expressions +// _tmp_245: yield_expr | star_expressions static void * -_tmp_243_rule(Parser *p) +_tmp_245_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40275,18 +40398,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // star_expressions @@ -40294,18 +40417,18 @@ _tmp_243_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions")); expr_ty star_expressions_var; if ( (star_expressions_var = star_expressions_rule(p)) // star_expressions ) { - D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); + D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions")); _res = star_expressions_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions")); } _res = NULL; @@ -40314,9 +40437,9 @@ _tmp_243_rule(Parser *p) return _res; } -// _tmp_244: '!' NAME +// _tmp_246: '!' NAME static void * -_tmp_244_rule(Parser *p) +_tmp_246_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40333,7 +40456,7 @@ _tmp_244_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); Token * _literal; expr_ty name_var; if ( @@ -40342,12 +40465,12 @@ _tmp_244_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); _res = _PyPegen_dummy_name(p, _literal, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); } _res = NULL; @@ -40356,9 +40479,9 @@ _tmp_244_rule(Parser *p) return _res; } -// _tmp_245: ':' | '}' +// _tmp_247: ':' | '}' static void * -_tmp_245_rule(Parser *p) +_tmp_247_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40375,18 +40498,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '}' @@ -40394,18 +40517,18 @@ _tmp_245_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; @@ -40414,9 +40537,9 @@ _tmp_245_rule(Parser *p) return _res; } -// _tmp_246: star_targets '=' +// _tmp_248: star_targets '=' static void * -_tmp_246_rule(Parser *p) +_tmp_248_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40433,7 +40556,7 @@ _tmp_246_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -40442,7 +40565,7 @@ _tmp_246_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40452,7 +40575,7 @@ _tmp_246_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -40461,9 +40584,9 @@ _tmp_246_rule(Parser *p) return _res; } -// _tmp_247: '.' | '...' +// _tmp_249: '.' | '...' static void * -_tmp_247_rule(Parser *p) +_tmp_249_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40480,18 +40603,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40499,18 +40622,18 @@ _tmp_247_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40519,9 +40642,9 @@ _tmp_247_rule(Parser *p) return _res; } -// _tmp_248: '.' | '...' +// _tmp_250: '.' | '...' static void * -_tmp_248_rule(Parser *p) +_tmp_250_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40538,18 +40661,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -40557,18 +40680,18 @@ _tmp_248_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -40577,9 +40700,9 @@ _tmp_248_rule(Parser *p) return _res; } -// _tmp_249: '@' named_expression NEWLINE +// _tmp_251: '@' named_expression NEWLINE static void * -_tmp_249_rule(Parser *p) +_tmp_251_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40596,7 +40719,7 @@ _tmp_249_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -40608,7 +40731,7 @@ _tmp_249_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40618,7 +40741,7 @@ _tmp_249_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -40627,9 +40750,9 @@ _tmp_249_rule(Parser *p) return _res; } -// _tmp_250: ',' expression +// _tmp_252: ',' expression static void * -_tmp_250_rule(Parser *p) +_tmp_252_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40646,7 +40769,7 @@ _tmp_250_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; expr_ty c; if ( @@ -40655,7 +40778,7 @@ _tmp_250_rule(Parser *p) (c = expression_rule(p)) // expression ) { - D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); + D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40665,7 +40788,7 @@ _tmp_250_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); } _res = NULL; @@ -40674,9 +40797,9 @@ _tmp_250_rule(Parser *p) return _res; } -// _tmp_251: ',' star_expression +// _tmp_253: ',' star_expression static void * -_tmp_251_rule(Parser *p) +_tmp_253_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40693,7 +40816,7 @@ _tmp_251_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -40702,7 +40825,7 @@ _tmp_251_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40712,7 +40835,7 @@ _tmp_251_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -40721,9 +40844,9 @@ _tmp_251_rule(Parser *p) return _res; } -// _tmp_252: 'or' conjunction +// _tmp_254: 'or' conjunction static void * -_tmp_252_rule(Parser *p) +_tmp_254_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40740,7 +40863,7 @@ _tmp_252_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -40749,7 +40872,7 @@ _tmp_252_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40759,7 +40882,7 @@ _tmp_252_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -40768,9 +40891,9 @@ _tmp_252_rule(Parser *p) return _res; } -// _tmp_253: 'and' inversion +// _tmp_255: 'and' inversion static void * -_tmp_253_rule(Parser *p) +_tmp_255_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40787,7 +40910,7 @@ _tmp_253_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -40796,7 +40919,7 @@ _tmp_253_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40806,7 +40929,7 @@ _tmp_253_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -40815,9 +40938,9 @@ _tmp_253_rule(Parser *p) return _res; } -// _tmp_254: slice | starred_expression +// _tmp_256: slice | starred_expression static void * -_tmp_254_rule(Parser *p) +_tmp_256_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40834,18 +40957,18 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } { // starred_expression @@ -40853,18 +40976,18 @@ _tmp_254_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } _res = NULL; @@ -40873,9 +40996,9 @@ _tmp_254_rule(Parser *p) return _res; } -// _tmp_255: fstring | string +// _tmp_257: fstring | string static void * -_tmp_255_rule(Parser *p) +_tmp_257_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40892,18 +41015,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -40911,18 +41034,18 @@ _tmp_255_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -40931,9 +41054,9 @@ _tmp_255_rule(Parser *p) return _res; } -// _tmp_256: 'if' disjunction +// _tmp_258: 'if' disjunction static void * -_tmp_256_rule(Parser *p) +_tmp_258_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40950,7 +41073,7 @@ _tmp_256_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -40959,7 +41082,7 @@ _tmp_256_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -40969,7 +41092,7 @@ _tmp_256_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -40978,9 +41101,9 @@ _tmp_256_rule(Parser *p) return _res; } -// _tmp_257: 'if' disjunction +// _tmp_259: 'if' disjunction static void * -_tmp_257_rule(Parser *p) +_tmp_259_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -40997,7 +41120,7 @@ _tmp_257_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); Token * _keyword; expr_ty z; if ( @@ -41006,7 +41129,7 @@ _tmp_257_rule(Parser *p) (z = disjunction_rule(p)) // disjunction ) { - D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41016,7 +41139,7 @@ _tmp_257_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); } _res = NULL; @@ -41025,9 +41148,9 @@ _tmp_257_rule(Parser *p) return _res; } -// _tmp_258: starred_expression | (assignment_expression | expression !':=') !'=' +// _tmp_260: starred_expression | (assignment_expression | expression !':=') !'=' static void * -_tmp_258_rule(Parser *p) +_tmp_260_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41044,18 +41167,18 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } { // (assignment_expression | expression !':=') !'=' @@ -41063,20 +41186,20 @@ _tmp_258_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_270_var; + D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_272_var; if ( - (_tmp_270_var = _tmp_270_rule(p)) // assignment_expression | expression !':=' + (_tmp_272_var = _tmp_272_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_270_var; + D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_272_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -41085,9 +41208,9 @@ _tmp_258_rule(Parser *p) return _res; } -// _tmp_259: ',' star_target +// _tmp_261: ',' star_target static void * -_tmp_259_rule(Parser *p) +_tmp_261_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41104,7 +41227,7 @@ _tmp_259_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -41113,7 +41236,7 @@ _tmp_259_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41123,7 +41246,7 @@ _tmp_259_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -41132,9 +41255,9 @@ _tmp_259_rule(Parser *p) return _res; } -// _tmp_260: ',' star_target +// _tmp_262: ',' star_target static void * -_tmp_260_rule(Parser *p) +_tmp_262_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41151,7 +41274,7 @@ _tmp_260_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -41160,7 +41283,7 @@ _tmp_260_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -41170,7 +41293,7 @@ _tmp_260_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -41179,9 +41302,9 @@ _tmp_260_rule(Parser *p) return _res; } -// _tmp_261: star_targets '=' +// _tmp_263: star_targets '=' static void * -_tmp_261_rule(Parser *p) +_tmp_263_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41198,7 +41321,7 @@ _tmp_261_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -41207,12 +41330,12 @@ _tmp_261_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -41221,9 +41344,9 @@ _tmp_261_rule(Parser *p) return _res; } -// _tmp_262: star_targets '=' +// _tmp_264: star_targets '=' static void * -_tmp_262_rule(Parser *p) +_tmp_264_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41240,7 +41363,7 @@ _tmp_262_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty star_targets_var; if ( @@ -41249,12 +41372,12 @@ _tmp_262_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = _PyPegen_dummy_name(p, star_targets_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -41263,9 +41386,9 @@ _tmp_262_rule(Parser *p) return _res; } -// _tmp_263: ')' | '**' +// _tmp_265: ')' | '**' static void * -_tmp_263_rule(Parser *p) +_tmp_265_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41282,18 +41405,18 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -41301,18 +41424,18 @@ _tmp_263_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -41321,9 +41444,9 @@ _tmp_263_rule(Parser *p) return _res; } -// _tmp_264: ':' | '**' +// _tmp_266: ':' | '**' static void * -_tmp_264_rule(Parser *p) +_tmp_266_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41340,18 +41463,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -41359,18 +41482,18 @@ _tmp_264_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -41379,9 +41502,9 @@ _tmp_264_rule(Parser *p) return _res; } -// _tmp_265: expression ['as' star_target] +// _tmp_267: expression ['as' star_target] static void * -_tmp_265_rule(Parser *p) +_tmp_267_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41398,22 +41521,22 @@ _tmp_265_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41422,9 +41545,9 @@ _tmp_265_rule(Parser *p) return _res; } -// _tmp_266: expressions ['as' star_target] +// _tmp_268: expressions ['as' star_target] static void * -_tmp_266_rule(Parser *p) +_tmp_268_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41441,22 +41564,22 @@ _tmp_266_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41465,9 +41588,9 @@ _tmp_266_rule(Parser *p) return _res; } -// _tmp_267: expression ['as' star_target] +// _tmp_269: expression ['as' star_target] static void * -_tmp_267_rule(Parser *p) +_tmp_269_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41484,22 +41607,22 @@ _tmp_267_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_275_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -41508,9 +41631,9 @@ _tmp_267_rule(Parser *p) return _res; } -// _tmp_268: expressions ['as' star_target] +// _tmp_270: expressions ['as' star_target] static void * -_tmp_268_rule(Parser *p) +_tmp_270_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41527,22 +41650,22 @@ _tmp_268_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_276_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -41551,9 +41674,9 @@ _tmp_268_rule(Parser *p) return _res; } -// _tmp_269: 'as' NAME +// _tmp_271: 'as' NAME static void * -_tmp_269_rule(Parser *p) +_tmp_271_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41570,7 +41693,7 @@ _tmp_269_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME")); Token * _keyword; expr_ty name_var; if ( @@ -41579,12 +41702,12 @@ _tmp_269_rule(Parser *p) (name_var = _PyPegen_name_token(p)) // NAME ) { - D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); + D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME")); _res = _PyPegen_dummy_name(p, _keyword, name_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME")); } _res = NULL; @@ -41593,9 +41716,9 @@ _tmp_269_rule(Parser *p) return _res; } -// _tmp_270: assignment_expression | expression !':=' +// _tmp_272: assignment_expression | expression !':=' static void * -_tmp_270_rule(Parser *p) +_tmp_272_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41612,18 +41735,18 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -41631,7 +41754,7 @@ _tmp_270_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -41639,12 +41762,12 @@ _tmp_270_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } _res = NULL; @@ -41653,9 +41776,9 @@ _tmp_270_rule(Parser *p) return _res; } -// _tmp_271: 'as' star_target +// _tmp_273: 'as' star_target static void * -_tmp_271_rule(Parser *p) +_tmp_273_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41672,7 +41795,7 @@ _tmp_271_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41681,12 +41804,12 @@ _tmp_271_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41695,9 +41818,9 @@ _tmp_271_rule(Parser *p) return _res; } -// _tmp_272: 'as' star_target +// _tmp_274: 'as' star_target static void * -_tmp_272_rule(Parser *p) +_tmp_274_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41714,7 +41837,7 @@ _tmp_272_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41723,12 +41846,12 @@ _tmp_272_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41737,9 +41860,9 @@ _tmp_272_rule(Parser *p) return _res; } -// _tmp_273: 'as' star_target +// _tmp_275: 'as' star_target static void * -_tmp_273_rule(Parser *p) +_tmp_275_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41756,7 +41879,7 @@ _tmp_273_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_275[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41765,12 +41888,12 @@ _tmp_273_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_275[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_275[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; @@ -41779,9 +41902,9 @@ _tmp_273_rule(Parser *p) return _res; } -// _tmp_274: 'as' star_target +// _tmp_276: 'as' star_target static void * -_tmp_274_rule(Parser *p) +_tmp_276_rule(Parser *p) { if (p->level++ == MAXSTACK) { p->error_indicator = 1; @@ -41798,7 +41921,7 @@ _tmp_274_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_276[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( @@ -41807,12 +41930,12 @@ _tmp_274_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_276[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_276[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; From d8f87cdf94a6533c5cf2d25e09e6fa3eb06720b9 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Fri, 23 Jun 2023 03:26:10 +0900 Subject: [PATCH 112/446] gh-101538: Add experimental wasi-threads build (#101537) Co-authored-by: Brett Cannon Co-authored-by: Erlend E. Aasland --- ...-02-03-21-36-42.gh-issue-101538.sF5F6S.rst | 1 + Python/thread_pthread.h | 8 +++++++ Tools/wasm/wasm_build.py | 8 ++++++- configure | 21 ++++++++++++++++++- configure.ac | 18 +++++++++++++++- 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst diff --git a/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst b/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst new file mode 100644 index 00000000000000..4b83c303b3d2c5 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-03-21-36-42.gh-issue-101538.sF5F6S.rst @@ -0,0 +1 @@ +Add experimental wasi-threads support. Patch by Takashi Yamamoto. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 76d6f3bcdf9c40..f96c57da64636d 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -356,7 +356,15 @@ PyThread_exit_thread(void) { if (!initialized) exit(0); +#if defined(__wasi__) + /* + * wasi-threads doesn't have pthread_exit right now + * cf. https://github.com/WebAssembly/wasi-threads/issues/7 + */ + abort(); +#else pthread_exit(0); +#endif } #ifdef USE_SEMAPHORES diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py index 241a5d4eed5ae8..c9947057a90754 100755 --- a/Tools/wasm/wasm_build.py +++ b/Tools/wasm/wasm_build.py @@ -480,7 +480,6 @@ def configure_cmd(self) -> List[str]: cmd.append(f"--{opt}-wasm-dynamic-linking") if self.pthreads is not None: - assert self.host.is_emscripten opt = "enable" if self.pthreads else "disable" cmd.append(f"--{opt}-wasm-pthreads") @@ -745,6 +744,13 @@ def build_emports(self, force: bool = False): support_level=SupportLevel.supported, host=Host.wasm32_wasi, ), + # wasm32-wasi-threads + BuildProfile( + "wasi-threads", + support_level=SupportLevel.experimental, + host=Host.wasm32_wasi, + pthreads=True, + ), # no SDK available yet # BuildProfile( # "wasm64-wasi", diff --git a/configure b/configure index fdc7c22531785a..e33bf77779e6e2 100755 --- a/configure +++ b/configure @@ -6874,7 +6874,11 @@ cat > conftest.c <>confdefs.h LIBS="$LIBS -lwasi-emulated-signal -lwasi-emulated-getpid -lwasi-emulated-process-clocks" echo "#define _WASI_EMULATED_SIGNAL 1" >> confdefs.h + if test "x$enable_wasm_pthreads" = xyes +then : + + # Note: update CFLAGS because ac_compile/ac_link needs this too. + # without this, configure fails to find pthread_create, sem_init, + # etc because they are only available in the sysroot for + # wasm32-wasi-threads. + as_fn_append CFLAGS " -target wasm32-wasi-threads -pthread" + as_fn_append CFLAGS_NODIST " -target wasm32-wasi-threads -pthread" + as_fn_append LDFLAGS_NODIST " -target wasm32-wasi-threads -pthread" + as_fn_append LDFLAGS_NODIST " -Wl,--import-memory" + as_fn_append LDFLAGS_NODIST " -Wl,--max-memory=10485760" + +fi + as_fn_append LDFLAGS_NODIST " -z stack-size=524288 -Wl,--stack-first -Wl,--initial-memory=10485760" ;; #( diff --git a/configure.ac b/configure.ac index a24cd689730d7a..8f097c41677598 100644 --- a/configure.ac +++ b/configure.ac @@ -1079,7 +1079,11 @@ cat > conftest.c <> confdefs.h + AS_VAR_IF([enable_wasm_pthreads], [yes], [ + # Note: update CFLAGS because ac_compile/ac_link needs this too. + # without this, configure fails to find pthread_create, sem_init, + # etc because they are only available in the sysroot for + # wasm32-wasi-threads. + AS_VAR_APPEND([CFLAGS], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([CFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -target wasm32-wasi-threads -pthread"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--import-memory"]) + AS_VAR_APPEND([LDFLAGS_NODIST], [" -Wl,--max-memory=10485760"]) + ]) + dnl increase initial memory and stack size, move stack first dnl https://github.com/WebAssembly/wasi-libc/issues/233 AS_VAR_APPEND([LDFLAGS_NODIST], [" -z stack-size=524288 -Wl,--stack-first -Wl,--initial-memory=10485760"]) From c38da1e3e19a7bf1053c6d52e730e970efeceff6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 22 Jun 2023 21:56:44 +0200 Subject: [PATCH 113/446] gh-105927: Add _PyWeakref_IS_DEAD() function (#105992) * Add _PyWeakref_IS_DEAD() internal function. * Modify is_dead_weakref() of Modules/_weakref.c and _pysqlite_drop_unused_cursor_references() to replace PyWeakref_GET_OBJECT() with _PyWeakref_IS_DEAD(). * Replace "int i" with "Py_ssize_t i" to iterate on cursors in _pysqlite_drop_unused_cursor_references(). --- Include/internal/pycore_weakref.h | 13 +++++++++++++ Modules/_sqlite/connection.c | 26 ++++++++++++++------------ Modules/_weakref.c | 5 +++-- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_weakref.h b/Include/internal/pycore_weakref.h index 4e2b979c91928b..f31b12463bb3e5 100644 --- a/Include/internal/pycore_weakref.h +++ b/Include/internal/pycore_weakref.h @@ -33,6 +33,19 @@ static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) { return Py_NewRef(obj); } +static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) { + assert(PyWeakref_Check(ref_obj)); + PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj); + PyObject *obj = ref->wr_object; + if (obj == Py_None) { + // clear_weakref() was called + return 1; + } + + // See _PyWeakref_GET_REF() for the rationale of this test + return (Py_REFCNT(obj) == 0); +} + #ifdef __cplusplus } #endif diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index d12d65500c654f..967ba2812080e5 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -21,6 +21,10 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "module.h" #include "structmember.h" // PyMemberDef #include "connection.h" @@ -29,6 +33,7 @@ #include "blob.h" #include "prepare_protocol.h" #include "util.h" +#include "pycore_weakref.h" // _PyWeakref_IS_DEAD() #include @@ -969,10 +974,6 @@ final_callback(sqlite3_context *context) static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) { - PyObject* new_list; - PyObject* weakref; - int i; - /* we only need to do this once in a while */ if (self->created_cursors++ < 200) { return; @@ -980,18 +981,19 @@ static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) self->created_cursors = 0; - new_list = PyList_New(0); + PyObject* new_list = PyList_New(0); if (!new_list) { return; } - for (i = 0; i < PyList_Size(self->cursors); i++) { - weakref = PyList_GetItem(self->cursors, i); - if (PyWeakref_GetObject(weakref) != Py_None) { - if (PyList_Append(new_list, weakref) != 0) { - Py_DECREF(new_list); - return; - } + for (Py_ssize_t i = 0; i < PyList_Size(self->cursors); i++) { + PyObject* weakref = PyList_GetItem(self->cursors, i); + if (_PyWeakref_IS_DEAD(weakref)) { + continue; + } + if (PyList_Append(new_list, weakref) != 0) { + Py_DECREF(new_list); + return; } } diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 387b8fa9d0a6f1..21ff0e2b7a984b 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -1,5 +1,6 @@ #include "Python.h" -#include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR +#include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR +#include "pycore_weakref.h" // _PyWeakref_IS_DEAD() #define GET_WEAKREFS_LISTPTR(o) \ @@ -43,7 +44,7 @@ is_dead_weakref(PyObject *value) PyErr_SetString(PyExc_TypeError, "not a weakref"); return -1; } - return PyWeakref_GET_OBJECT(value) == Py_None; + return _PyWeakref_IS_DEAD(value); } /*[clinic input] From 46a3190fcf8580f322047395408cd60feba67041 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 22 Jun 2023 22:31:31 +0200 Subject: [PATCH 114/446] gh-105927: Avoid calling PyWeakref_GET_OBJECT() (#105997) * Replace PyWeakref_GET_OBJECT() with _PyWeakref_GET_REF(). * _sqlite/blob.c now holds a strong reference to the blob object while calling close_blob(). * _xidregistry_find_type() now holds a strong reference to registered while using it. --- Modules/_sqlite/blob.c | 13 ++++++++++--- Objects/weakrefobject.c | 6 +++++- Python/pystate.c | 9 ++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Modules/_sqlite/blob.c b/Modules/_sqlite/blob.c index 3096fb0c2135e4..989d9a83b590ca 100644 --- a/Modules/_sqlite/blob.c +++ b/Modules/_sqlite/blob.c @@ -1,5 +1,10 @@ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "blob.h" #include "util.h" +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self))) #include "clinic/blob.c.h" @@ -97,10 +102,12 @@ pysqlite_close_all_blobs(pysqlite_Connection *self) { for (int i = 0; i < PyList_GET_SIZE(self->blobs); i++) { PyObject *weakref = PyList_GET_ITEM(self->blobs, i); - PyObject *blob = PyWeakref_GetObject(weakref); - if (!Py_IsNone(blob)) { - close_blob((pysqlite_Blob *)blob); + PyObject *blob = _PyWeakref_GET_REF(weakref); + if (blob == NULL) { + continue; } + close_blob((pysqlite_Blob *)blob); + Py_DECREF(blob); } } diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 49342d0658de6b..c54f663acdb66c 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -140,7 +140,11 @@ weakref_vectorcall(PyObject *self, PyObject *const *args, if (!_PyArg_CheckPositional("weakref", nargs, 0, 0)) { return NULL; } - return Py_NewRef(PyWeakref_GET_OBJECT(self)); + PyObject *obj = _PyWeakref_GET_REF(self); + if (obj == NULL) { + Py_RETURN_NONE; + } + return obj; } static Py_hash_t diff --git a/Python/pystate.c b/Python/pystate.c index 2c39ac9eb8d171..20b02ef22109e7 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -13,7 +13,8 @@ #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" #include "pycore_runtime_init.h" // _PyRuntimeState_INIT -#include "pycore_sysmodule.h" +#include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() /* -------------------------------------------------------------------------- CAUTION @@ -2589,16 +2590,18 @@ _xidregistry_find_type(struct _xidregistry *xidregistry, PyTypeObject *cls) { struct _xidregitem *cur = xidregistry->head; while (cur != NULL) { - PyObject *registered = PyWeakref_GetObject(cur->cls); - if (registered == Py_None) { + PyObject *registered = _PyWeakref_GET_REF(cur->cls); + if (registered == NULL) { // The weakly ref'ed object was freed. cur = _xidregistry_remove_entry(xidregistry, cur); } else { assert(PyType_Check(registered)); if (registered == (PyObject *)cls) { + Py_DECREF(registered); return cur; } + Py_DECREF(registered); cur = cur->next; } } From cd5280367a3a7065d13b8f7234474f7a2e9a18fd Mon Sep 17 00:00:00 2001 From: chgnrdv <52372310+chgnrdv@users.noreply.github.com> Date: Fri, 23 Jun 2023 00:30:19 +0300 Subject: [PATCH 115/446] gh-105979: Fix exception handling in `unmarshal_frozen_code` (`Python/import.c`) (#105980) --- Lib/test/test_import/__init__.py | 8 ++++++++ .../2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst | 1 + Python/import.c | 1 + 3 files changed, 10 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index f2726da203efbd..e0e2354ae2f19f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -23,6 +23,7 @@ import unittest from unittest import mock import _testinternalcapi +import _imp from test.support import os_helper from test.support import ( @@ -763,6 +764,13 @@ def test_dll_dependency_import(self): env=env, cwd=os.path.dirname(pyexe)) + def test_issue105979(self): + # this used to crash + with self.assertRaises(ImportError) as cm: + _imp.get_frozen_object("x", b"6\'\xd5Cu\x12") + self.assertIn("Frozen object named 'x' is invalid", + str(cm.exception)) + @skip_if_dont_write_bytecode class FilePermissionTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst new file mode 100644 index 00000000000000..be6962afd0c78f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-19-16-24.gh-issue-105979.TDP2CU.rst @@ -0,0 +1 @@ +Fix crash in :func:`!_imp.get_frozen_object` due to improper exception handling. diff --git a/Python/import.c b/Python/import.c index 969902afea1cd6..9b1ad87b84f649 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2071,6 +2071,7 @@ unmarshal_frozen_code(PyInterpreterState *interp, struct frozen_info *info) PyObject *co = PyMarshal_ReadObjectFromString(info->data, info->size); if (co == NULL) { /* Does not contain executable code. */ + PyErr_Clear(); set_frozen_error(FROZEN_INVALID, info->nameobj); return NULL; } From 403a574b000569ea2c91f5325e6a8061a29e64bf Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 22 Jun 2023 15:02:38 -0700 Subject: [PATCH 116/446] Test specialization's thread-safety (GH-105953) --- Lib/test/test_opcache.py | 512 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 511 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 5281eb77c02d1b..2f6f91ded248bb 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -1,3 +1,6 @@ +import dis +import threading +import types import unittest @@ -481,6 +484,513 @@ def f(x, y): f() +class TestRacesDoNotCrash(unittest.TestCase): + # Careful with these. Bigger numbers have a higher chance of catching bugs, + # but you can also burn through a *ton* of type/dict/function versions: + ITEMS = 1000 + LOOPS = 4 + WARMUPS = 2 + WRITERS = 2 + + def assert_specialized(self, f, opname): + instructions = dis.get_instructions(f, adaptive=True) + opnames = {instruction.opname for instruction in instructions} + self.assertIn(opname, opnames) + + def assert_races_do_not_crash( + self, opname, get_items, read, write, *, check_items=False + ): + # This might need a few dozen loops in some cases: + for _ in range(self.LOOPS): + items = get_items() + # Reset: + if check_items: + for item in items: + item.__code__ = item.__code__.replace() + else: + read.__code__ = read.__code__.replace() + # Specialize: + for _ in range(self.WARMUPS): + read(items) + if check_items: + for item in items: + self.assert_specialized(item, opname) + else: + self.assert_specialized(read, opname) + # Create writers: + writers = [] + for _ in range(self.WRITERS): + writer = threading.Thread(target=write, args=[items]) + writers.append(writer) + # Run: + for writer in writers: + writer.start() + read(items) # BOOM! + for writer in writers: + writer.join() + + def test_binary_subscr_getitem(self): + def get_items(): + class C: + __getitem__ = lambda self, item: None + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item[None] + except TypeError: + pass + + def write(items): + for item in items: + try: + del item.__getitem__ + except AttributeError: + pass + type(item).__getitem__ = lambda self, item: None + + opname = "BINARY_SUBSCR_GETITEM" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_binary_subscr_list_int(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = [None] + items.append(item) + return items + + def read(items): + for item in items: + try: + item[0] + except IndexError: + pass + + def write(items): + for item in items: + item.clear() + item.append(None) + + opname = "BINARY_SUBSCR_LIST_INT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_for_iter_gen(self): + def get_items(): + def g(): + yield + yield + + items = [] + for _ in range(self.ITEMS): + item = g() + items.append(item) + return items + + def read(items): + for item in items: + try: + for _ in item: + break + except ValueError: + pass + + def write(items): + for item in items: + try: + for _ in item: + break + except ValueError: + pass + + opname = "FOR_ITER_GEN" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_for_iter_list(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = [None] + items.append(item) + return items + + def read(items): + for item in items: + for item in item: + break + + def write(items): + for item in items: + item.clear() + item.append(None) + + opname = "FOR_ITER_LIST" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_class(self): + def get_items(): + class C: + a = object() + + items = [] + for _ in range(self.ITEMS): + item = C + items.append(item) + return items + + def read(items): + for item in items: + try: + item.a + except AttributeError: + pass + + def write(items): + for item in items: + try: + del item.a + except AttributeError: + pass + item.a = object() + + opname = "LOAD_ATTR_CLASS" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_getattribute_overridden(self): + def get_items(): + class C: + __getattribute__ = lambda self, name: None + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item.a + except AttributeError: + pass + + def write(items): + for item in items: + try: + del item.__getattribute__ + except AttributeError: + pass + type(item).__getattribute__ = lambda self, name: None + + opname = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_instance_value(self): + def get_items(): + class C: + pass + + items = [] + for _ in range(self.ITEMS): + item = C() + item.a = None + items.append(item) + return items + + def read(items): + for item in items: + item.a + + def write(items): + for item in items: + item.__dict__[None] = None + + opname = "LOAD_ATTR_INSTANCE_VALUE" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_method_lazy_dict(self): + def get_items(): + class C(Exception): + m = lambda self: None + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item.m() + except AttributeError: + pass + + def write(items): + for item in items: + try: + del item.m + except AttributeError: + pass + type(item).m = lambda self: None + + opname = "LOAD_ATTR_METHOD_LAZY_DICT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_method_no_dict(self): + def get_items(): + class C: + __slots__ = () + m = lambda self: None + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item.m() + except AttributeError: + pass + + def write(items): + for item in items: + try: + del item.m + except AttributeError: + pass + type(item).m = lambda self: None + + opname = "LOAD_ATTR_METHOD_NO_DICT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_method_with_values(self): + def get_items(): + class C: + m = lambda self: None + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item.m() + except AttributeError: + pass + + def write(items): + for item in items: + try: + del item.m + except AttributeError: + pass + type(item).m = lambda self: None + + opname = "LOAD_ATTR_METHOD_WITH_VALUES" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_module(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = types.ModuleType("") + items.append(item) + return items + + def read(items): + for item in items: + try: + item.__name__ + except AttributeError: + pass + + def write(items): + for item in items: + d = item.__dict__.copy() + item.__dict__.clear() + item.__dict__.update(d) + + opname = "LOAD_ATTR_MODULE" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_property(self): + def get_items(): + class C: + a = property(lambda self: None) + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + try: + item.a + except AttributeError: + pass + + def write(items): + for item in items: + try: + del type(item).a + except AttributeError: + pass + type(item).a = property(lambda self: None) + + opname = "LOAD_ATTR_PROPERTY" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_attr_with_hint(self): + def get_items(): + class C: + pass + + items = [] + for _ in range(self.ITEMS): + item = C() + item.__dict__ + item.a = None + items.append(item) + return items + + def read(items): + for item in items: + item.a + + def write(items): + for item in items: + item.__dict__[None] = None + + opname = "LOAD_ATTR_WITH_HINT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_load_global_module(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = eval("lambda: x", {"x": None}) + items.append(item) + return items + + def read(items): + for item in items: + item() + + def write(items): + for item in items: + item.__globals__[None] = None + + opname = "LOAD_GLOBAL_MODULE" + self.assert_races_do_not_crash( + opname, get_items, read, write, check_items=True + ) + + def test_store_attr_instance_value(self): + def get_items(): + class C: + pass + + items = [] + for _ in range(self.ITEMS): + item = C() + items.append(item) + return items + + def read(items): + for item in items: + item.a = None + + def write(items): + for item in items: + item.__dict__[None] = None + + opname = "STORE_ATTR_INSTANCE_VALUE" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_store_attr_with_hint(self): + def get_items(): + class C: + pass + + items = [] + for _ in range(self.ITEMS): + item = C() + item.__dict__ + items.append(item) + return items + + def read(items): + for item in items: + item.a = None + + def write(items): + for item in items: + item.__dict__[None] = None + + opname = "STORE_ATTR_WITH_HINT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_store_subscr_list_int(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = [None] + items.append(item) + return items + + def read(items): + for item in items: + try: + item[0] = None + except IndexError: + pass + + def write(items): + for item in items: + item.clear() + item.append(None) + + opname = "STORE_SUBSCR_LIST_INT" + self.assert_races_do_not_crash(opname, get_items, read, write) + + def test_unpack_sequence_list(self): + def get_items(): + items = [] + for _ in range(self.ITEMS): + item = [None] + items.append(item) + return items + + def read(items): + for item in items: + try: + [_] = item + except ValueError: + pass + + def write(items): + for item in items: + item.clear() + item.append(None) + + opname = "UNPACK_SEQUENCE_LIST" + self.assert_races_do_not_crash(opname, get_items, read, write) + + if __name__ == "__main__": - import unittest unittest.main() From 193a2b2eaab9890f2cb16128c95bb63cb49307f1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 23 Jun 2023 00:04:39 +0200 Subject: [PATCH 117/446] gh-105922: Use PyImport_AddModuleRef() function (#105999) Replace PyImport_AddModuleObject() + Py_XNewRef() with PyImport_AddModuleRef() to get directly a strong reference. --- Python/import.c | 3 +-- Python/pythonrun.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Python/import.c b/Python/import.c index 9b1ad87b84f649..05da9506cc0b64 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1382,8 +1382,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) if (_PyUnicode_EqualToASCIIString(name, p->name)) { if (p->initfunc == NULL) { /* Cannot re-init internal module ("sys" or "builtins") */ - mod = PyImport_AddModuleObject(name); - return Py_XNewRef(mod); + return import_add_module(tstate, name); } mod = _PyImport_InitFunc_TrampolineCall(*p->initfunc); if (mod == NULL) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c index af82fa491511c1..2986622a8b0dcf 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -276,7 +276,7 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, return parse_res; } - PyObject *main_module = Py_XNewRef(PyImport_AddModuleObject(&_Py_ID(__main__))); + PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { _PyArena_Free(arena); return -1; From ee52158f209835d6d4ca27f44218466f266f4afb Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 23 Jun 2023 01:23:08 +0200 Subject: [PATCH 118/446] gh-105927: PyImport_AddModule() uses _PyWeakref_GET_REF() (#106001) It now raises an exception if sys.modules doesn't hold a strong reference to the module. Elaborate the comment explaining why a weak reference is used to create a borrowed reference. --- Python/import.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Python/import.c b/Python/import.c index 05da9506cc0b64..97da8bba8adff9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -12,6 +12,7 @@ #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() +#include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "marshal.h" // PyMarshal_ReadObjectFromString() #include "importdl.h" // _PyImport_DynLoadFiletab #include "pydtrace.h" // PyDTrace_IMPORT_FIND_LOAD_START_ENABLED() @@ -373,15 +374,30 @@ PyImport_AddModuleObject(PyObject *name) return NULL; } - // gh-86160: PyImport_AddModuleObject() returns a borrowed reference + // gh-86160: PyImport_AddModuleObject() returns a borrowed reference. + // Create a weak reference to produce a borrowed reference, since it can + // become NULL. sys.modules type can be different than dict and it is not + // guaranteed that it keeps a strong reference to the module. It can be a + // custom mapping with __getitem__() which returns a new object or removes + // returned object, or __setitem__ which does nothing. There is so much + // unknown. With weakref we can be sure that we get either a reference to + // live object or NULL. + // + // Use PyImport_AddModuleRef() to avoid these issues. PyObject *ref = PyWeakref_NewRef(mod, NULL); Py_DECREF(mod); if (ref == NULL) { return NULL; } - - mod = PyWeakref_GetObject(ref); + mod = _PyWeakref_GET_REF(ref); Py_DECREF(ref); + Py_XDECREF(mod); + + if (mod == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, + "sys.modules does not hold a strong reference " + "to the module"); + } return mod; /* borrowed reference */ } From 7b3ed5b29fd33ecfdaedc3bb0b8f6c05ded68361 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 23 Jun 2023 03:02:02 +0200 Subject: [PATCH 119/446] gh-105927: _ssl GET_SOCKET() uses _PyWeakref_GET_REF() (#106002) --- Modules/_ssl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 9ce61a651c2cbb..4254fde0f5190b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -383,10 +383,20 @@ typedef enum { #define ERRSTR1(x,y,z) (x ":" y ": " z) #define ERRSTR(x) ERRSTR1("_ssl.c", Py_STRINGIFY(__LINE__), x) -/* Get the socket from a PySSLSocket, if it has one */ +// Get the socket from a PySSLSocket, if it has one. +// Return a borrowed reference. static inline PySocketSockObject* GET_SOCKET(PySSLSocket *obj) { if (obj->Socket) { - return (PySocketSockObject *)PyWeakref_GetObject(obj->Socket); + PyObject *sock = _PyWeakref_GET_REF(obj->Socket); + if (sock != NULL) { + // GET_SOCKET() returns a borrowed reference + Py_DECREF(sock); + } + else { + // dead weak reference + sock = Py_None; + } + return (PySocketSockObject *)sock; // borrowed reference } else { return NULL; From 6a80664ef1200008d5beb1584e03d779ef30cc58 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 23 Jun 2023 05:00:56 +0200 Subject: [PATCH 120/446] gh-105927: Remove _PyWeakref_GetWeakrefCount() (#106007) Remove _PyWeakref_GetWeakrefCount() and _PyWeakref_ClearRef() from the public C API: move them to the internal C API. Refactor also _weakref_getweakrefs() code to make it more readable. --- Include/cpython/weakrefobject.h | 4 ---- Include/internal/pycore_weakref.h | 4 ++++ Modules/_weakref.c | 33 ++++++++++++++----------------- Modules/gcmodule.c | 1 + 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h index fd79fdc2dcc468..6bf16553814252 100644 --- a/Include/cpython/weakrefobject.h +++ b/Include/cpython/weakrefobject.h @@ -32,10 +32,6 @@ struct _PyWeakReference { vectorcallfunc vectorcall; }; -PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head); - -PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); - static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) { PyWeakReference *ref; PyObject *obj; diff --git a/Include/internal/pycore_weakref.h b/Include/internal/pycore_weakref.h index f31b12463bb3e5..51b2bb6b11ede9 100644 --- a/Include/internal/pycore_weakref.h +++ b/Include/internal/pycore_weakref.h @@ -46,6 +46,10 @@ static inline int _PyWeakref_IS_DEAD(PyObject *ref_obj) { return (Py_REFCNT(obj) == 0); } +extern Py_ssize_t _PyWeakref_GetWeakrefCount(PyWeakReference *head); + +extern void _PyWeakref_ClearRef(PyWeakReference *self); + #ifdef __cplusplus } #endif diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 21ff0e2b7a984b..b5d80cbd731a28 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -89,25 +89,22 @@ static PyObject * _weakref_getweakrefs(PyObject *module, PyObject *object) /*[clinic end generated code: output=25c7731d8e011824 input=00c6d0e5d3206693]*/ { - PyObject *result = NULL; - - if (_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) { - PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); - Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list); - - result = PyList_New(count); - if (result != NULL) { - PyWeakReference *current = *list; - Py_ssize_t i; - for (i = 0; i < count; ++i) { - PyList_SET_ITEM(result, i, (PyObject *) current); - Py_INCREF(current); - current = current->wr_next; - } - } + if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) { + return PyList_New(0); } - else { - result = PyList_New(0); + + PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); + Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list); + + PyObject *result = PyList_New(count); + if (result == NULL) { + return NULL; + } + + PyWeakReference *current = *list; + for (Py_ssize_t i = 0; i < count; ++i) { + PyList_SET_ITEM(result, i, Py_NewRef(current)); + current = current->wr_next; } return result; } diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index c51c100be8361d..97644a7cee774f 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -30,6 +30,7 @@ #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_weakref.h" // _PyWeakref_ClearRef() #include "pydtrace.h" typedef struct _gc_runtime_state GCState; From a72683ba8e0337650cc490dbe593a5e46aba60cb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 23 Jun 2023 08:58:45 +0100 Subject: [PATCH 121/446] Docs: Avoid a DeprecationWarning in `pyspecific.py` when running with Sphinx >=6.1 (#105886) Co-authored-by: Hugo van Kemenade --- Doc/tools/extensions/pyspecific.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 8a2eb07a69a69a..795aeed1007a79 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -14,29 +14,27 @@ from os import getenv, path from time import asctime from pprint import pformat + +from docutils import nodes, utils from docutils.io import StringOutput from docutils.parsers.rst import Directive from docutils.utils import new_document - -from docutils import nodes, utils - from sphinx import addnodes from sphinx.builders import Builder -try: - from sphinx.errors import NoUri -except ImportError: - from sphinx.environment import NoUri +from sphinx.domains.python import PyFunction, PyMethod +from sphinx.errors import NoUri from sphinx.locale import _ as sphinx_gettext -from sphinx.util import status_iterator, logging +from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import split_explicit_title from sphinx.writers.text import TextWriter, TextTranslator try: - from sphinx.domains.python import PyFunction, PyMethod + # Sphinx 6+ + from sphinx.util.display import status_iterator except ImportError: - from sphinx.domains.python import PyClassmember as PyMethod - from sphinx.domains.python import PyModulelevel as PyFunction + # Deprecated in Sphinx 6.1, will be removed in Sphinx 8 + from sphinx.util import status_iterator ISSUE_URI = 'https://bugs.python.org/issue?@action=redirect&bpo=%s' From 9339d70ac2d45743507e320e81e68acf77e366af Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 23 Jun 2023 13:18:29 +0100 Subject: [PATCH 122/446] GH-106012: Fix monitoring of static code objects (GH-106017) --- Python/instrumentation.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 524a82c076e99d..86d014ededc8ee 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -903,26 +903,34 @@ instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) #endif static inline uint8_t -get_tools_for_instruction(PyCodeObject * code, int i, int event) +get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i, int event) { uint8_t tools; assert(event != PY_MONITORING_EVENT_LINE); assert(event != PY_MONITORING_EVENT_INSTRUCTION); - assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code)); - _PyCoMonitoringData *monitoring = code->_co_monitoring; if (event >= PY_MONITORING_UNGROUPED_EVENTS) { assert(event == PY_MONITORING_EVENT_C_RAISE || event == PY_MONITORING_EVENT_C_RETURN); event = PY_MONITORING_EVENT_CALL; } - if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) { - tools = monitoring->tools[i]; + if (event < PY_MONITORING_INSTRUMENTED_EVENTS) { + CHECK(is_version_up_to_date(code, interp)); + CHECK(instrumentation_cross_checks(interp, code)); + if (code->_co_monitoring->tools) { + tools = code->_co_monitoring->tools[i]; + } + else { + tools = code->_co_monitoring->active_monitors.tools[event]; + } } else { - tools = code->_co_monitoring->active_monitors.tools[event]; + if (code->_co_monitoring) { + tools = code->_co_monitoring->active_monitors.tools[event]; + } + else { + tools = interp->monitors.tools[event]; + } } - CHECK(tools_is_subset_for_event(code, event, tools)); - CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools); return tools; } @@ -937,9 +945,6 @@ call_instrumentation_vector( assert(!_PyErr_Occurred(tstate)); assert(args[0] == NULL); PyCodeObject *code = _PyFrame_GetCode(frame); - assert(code->_co_instrumentation_version == tstate->interp->monitoring_version); - assert(is_version_up_to_date(code, tstate->interp)); - assert(instrumentation_cross_checks(tstate->interp, code)); assert(args[1] == NULL); args[1] = (PyObject *)code; int offset = (int)(instr - _PyCode_CODE(code)); @@ -952,11 +957,11 @@ call_instrumentation_vector( } assert(args[2] == NULL); args[2] = offset_obj; - uint8_t tools = get_tools_for_instruction(code, offset, event); + PyInterpreterState *interp = tstate->interp; + uint8_t tools = get_tools_for_instruction(code, interp, offset, event); Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; PyObject **callargs = &args[1]; int err = 0; - PyInterpreterState *interp = tstate->interp; while (tools) { int tool = most_significant_bit(tools); assert(tool >= 0 && tool < 8); From 37c5c40125389c71e40b16441fbc72ba01be5fb4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 23 Jun 2023 15:39:50 +0200 Subject: [PATCH 123/446] gh-85136: Remove disabled remote IMAP tests (#106022) Tests had been disabled since Jun 12, 2020 (gh-20836). --- Lib/test/test_imaplib.py | 95 ---------------------------------------- 1 file changed, 95 deletions(-) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 60f5b671b1da48..2b2f1f76d26db3 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -965,100 +965,5 @@ def test_ssl_verified(self): client.shutdown() -@unittest.skipUnless( - support.is_resource_enabled('network'), 'network resource disabled') -@unittest.skip('cyrus.andrew.cmu.edu blocks connections') -class RemoteIMAPTest(unittest.TestCase): - host = 'cyrus.andrew.cmu.edu' - port = 143 - username = 'anonymous' - password = 'pass' - imap_class = imaplib.IMAP4 - - def setUp(self): - with socket_helper.transient_internet(self.host): - self.server = self.imap_class(self.host, self.port) - - def tearDown(self): - if self.server is not None: - with socket_helper.transient_internet(self.host): - self.server.logout() - - def test_logincapa(self): - with socket_helper.transient_internet(self.host): - for cap in self.server.capabilities: - self.assertIsInstance(cap, str) - self.assertIn('LOGINDISABLED', self.server.capabilities) - self.assertIn('AUTH=ANONYMOUS', self.server.capabilities) - rs = self.server.login(self.username, self.password) - self.assertEqual(rs[0], 'OK') - - def test_logout(self): - with socket_helper.transient_internet(self.host): - rs = self.server.logout() - self.server = None - self.assertEqual(rs[0], 'BYE', rs) - - -@unittest.skipUnless(ssl, "SSL not available") -@unittest.skipUnless( - support.is_resource_enabled('network'), 'network resource disabled') -@unittest.skip('cyrus.andrew.cmu.edu blocks connections') -class RemoteIMAP_STARTTLSTest(RemoteIMAPTest): - - def setUp(self): - super().setUp() - with socket_helper.transient_internet(self.host): - rs = self.server.starttls() - self.assertEqual(rs[0], 'OK') - - def test_logincapa(self): - for cap in self.server.capabilities: - self.assertIsInstance(cap, str) - self.assertNotIn('LOGINDISABLED', self.server.capabilities) - - -@unittest.skipUnless(ssl, "SSL not available") -@unittest.skip('cyrus.andrew.cmu.edu blocks connections') -class RemoteIMAP_SSLTest(RemoteIMAPTest): - port = 993 - imap_class = IMAP4_SSL - - def setUp(self): - pass - - def tearDown(self): - pass - - def create_ssl_context(self): - ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - ssl_context.load_cert_chain(CERTFILE) - return ssl_context - - def check_logincapa(self, server): - try: - for cap in server.capabilities: - self.assertIsInstance(cap, str) - self.assertNotIn('LOGINDISABLED', server.capabilities) - self.assertIn('AUTH=PLAIN', server.capabilities) - rs = server.login(self.username, self.password) - self.assertEqual(rs[0], 'OK') - finally: - server.logout() - - def test_logincapa(self): - with socket_helper.transient_internet(self.host): - _server = self.imap_class(self.host, self.port) - self.check_logincapa(_server) - - def test_logout(self): - with socket_helper.transient_internet(self.host): - _server = self.imap_class(self.host, self.port) - rs = _server.logout() - self.assertEqual(rs[0], 'BYE', rs) - - if __name__ == "__main__": unittest.main() From 968435ddb1c1af9333befb26f7970cded8a5c710 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 23 Jun 2023 15:33:20 +0100 Subject: [PATCH 124/446] Typing docs: improve the guidance on annotating tuples (#106021) --- Doc/library/typing.rst | 93 ++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index dfd071fa136945..7458fa568b3253 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -346,6 +346,68 @@ Or by using the :class:`TypeVar` factory directly:: .. versionchanged:: 3.12 Syntactic support for generics is new in Python 3.12. +.. _annotating-tuples: + +Annotating tuples +================= + +For most containers in Python, the typing system assumes that all elements in +the container will be of the same type. For example:: + + from collections.abc import Mapping + + # Type checker will infer that all elements in ``x`` are meant to be ints + x: list[int] = [] + + # Type checker error: ``list`` only accepts a single type argument: + y: list[int, str] = [1, 'foo'] + + # Type checker will infer that all keys in ``y`` are meant to be strings, + # and that all values in ``y`` are meant to be either strings or ints + z: Mapping[str, str | int] = {} + +:class:`list` only accepts one type argument, so a type checker would emit an +error on the ``y`` assignment above. Similarly, +:class:`~collections.abc.Mapping` only accepts two type arguments: the first +indicates the type of the keys, and the second indicates the type of the +values. + +Unlike most other Python containers, however, it is common in idiomatic Python +code for tuples to have elements which are not all of the same type. For this +reason, tuples are special-cased in Python's typing system. :class:`tuple` +accepts *any number* of type arguments:: + + # OK: ``x`` is assigned to a tuple of length 1 where the sole element is an int + x: tuple[int] = (5,) + + # OK: ``y`` is assigned to a tuple of length 2; + # element 1 is an int, element 2 is a str + y: tuple[int, str] = (5, "foo") + + # Error: the type annotation indicates a tuple of length 1, + # but ``z`` has been assigned to a tuple of length 3 + z: tuple[int] = (1, 2, 3) + +To denote a tuple which could be of *any* length, and in which all elements are +of the same type ``T``, use ``tuple[T, ...]``. To denote an empty tuple, use +``tuple[()]``. Using plain ``tuple`` as an annotation is equivalent to using +``tuple[Any, ...]``:: + + x: tuple[int, ...] = (1, 2) + # These reassignments are OK: ``tuple[int, ...]`` indicates x can be of any length + x = (1, 2, 3) + x = () + # This reassignment is an error: all elements in ``x`` must be ints + x = ("foo", "bar") + + # ``y`` can only ever be assigned to an empty tuple + y: tuple[()] = () + + z: tuple = ("foo", "bar") + # These reassignments are OK: plain ``tuple`` is equivalent to ``tuple[Any, ...]`` + z = (1, 2, 3) + z = () + .. _user-defined-generics: User-defined generic types @@ -877,26 +939,6 @@ Special forms These can be used as types in annotations. They all support subscription using ``[]``, but each has a unique syntax. -.. data:: Tuple - - Deprecated alias for :class:`tuple`. - - ``Tuple[X, Y]`` is the type of a tuple of two items - with the first item of type X and the second of type Y. The type of - the empty tuple can be written as ``Tuple[()]``. - - Example: ``Tuple[T1, T2]`` is a tuple of two elements corresponding - to type variables T1 and T2. ``Tuple[int, float, str]`` is a tuple - of an int, a float and a string. - - To specify a variable-length tuple of homogeneous type, - use literal ellipsis, e.g. ``Tuple[int, ...]``. A plain ``Tuple`` annotation - is equivalent to ``tuple``, ``Tuple[Any, ...]``, or ``tuple[Any, ...]``. - - .. deprecated:: 3.9 - :class:`builtins.tuple ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - .. data:: Union Union type; ``Union[X, Y]`` is equivalent to ``X | Y`` and means either X or Y. @@ -3136,7 +3178,16 @@ Aliases to built-in types now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. -.. note:: :data:`Tuple` is a special form. +.. data:: Tuple + + Deprecated alias for :class:`tuple`. + + :class:`tuple` and ``Tuple`` are special-cased in the type system; see + :ref:`annotating-tuples` for more details. + + .. deprecated:: 3.9 + :class:`builtins.tuple ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. .. _corresponding-to-types-in-collections: From 9499b0f138cc53b9a2590350d0b545d2f69ee126 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 23 Jun 2023 15:59:25 +0100 Subject: [PATCH 125/446] gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom `__subclasshook__` methods (#105976) --- Lib/test/test_typing.py | 40 ++++++++++++ Lib/typing.py | 65 ++++++++++--------- ...-06-21-19-04-27.gh-issue-105974.M47n3t.rst | 6 ++ 3 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ad67568770970f..1df21926d1f67e 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3477,6 +3477,46 @@ def __subclasshook__(cls, other): self.assertIsSubclass(OKClass, C) self.assertNotIsSubclass(BadClass, C) + def test_custom_subclasshook_2(self): + @runtime_checkable + class HasX(Protocol): + # The presence of a non-callable member + # would mean issubclass() checks would fail with TypeError + # if it weren't for the custom `__subclasshook__` method + x = 1 + + @classmethod + def __subclasshook__(cls, other): + return hasattr(other, 'x') + + class Empty: pass + + class ImplementsHasX: + x = 1 + + self.assertIsInstance(ImplementsHasX(), HasX) + self.assertNotIsInstance(Empty(), HasX) + self.assertIsSubclass(ImplementsHasX, HasX) + self.assertNotIsSubclass(Empty, HasX) + + # isinstance() and issubclass() checks against this still raise TypeError, + # despite the presence of the custom __subclasshook__ method, + # as it's not decorated with @runtime_checkable + class NotRuntimeCheckable(Protocol): + @classmethod + def __subclasshook__(cls, other): + return hasattr(other, 'x') + + must_be_runtime_checkable = ( + "Instance and class checks can only be used " + "with @runtime_checkable protocols" + ) + + with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): + issubclass(object, NotRuntimeCheckable) + with self.assertRaisesRegex(TypeError, must_be_runtime_checkable): + isinstance(object(), NotRuntimeCheckable) + def test_issubclass_fails_correctly(self): @runtime_checkable class P(Protocol): diff --git a/Lib/typing.py b/Lib/typing.py index 1dd9398344639b..9187b74b0e2e1f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1818,14 +1818,17 @@ def __init__(cls, *args, **kwargs): def __subclasscheck__(cls, other): if cls is Protocol: return type.__subclasscheck__(cls, other) - if not isinstance(other, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') if ( getattr(cls, '_is_protocol', False) and not _allow_reckless_class_checks() ): - if not cls.__callable_proto_members_only__: + if not isinstance(other, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + if ( + not cls.__callable_proto_members_only__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): raise TypeError( "Protocols with non-method members don't support issubclass()" ) @@ -1869,6 +1872,30 @@ def __instancecheck__(cls, instance): return False +@classmethod +def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if (isinstance(annotations, collections.abc.Mapping) and + attr in annotations and + issubclass(other, Generic) and getattr(other, '_is_protocol', False)): + break + else: + return NotImplemented + return True + + class Protocol(Generic, metaclass=_ProtocolMeta): """Base class for protocol classes. @@ -1914,37 +1941,11 @@ def __init_subclass__(cls, *args, **kwargs): cls._is_protocol = any(b is Protocol for b in cls.__bases__) # Set (or override) the protocol subclass hook. - def _proto_hook(other): - if not cls.__dict__.get('_is_protocol', False): - return NotImplemented - - for attr in cls.__protocol_attrs__: - for base in other.__mro__: - # Check if the members appears in the class dictionary... - if attr in base.__dict__: - if base.__dict__[attr] is None: - return NotImplemented - break - - # ...or in annotations, if it is a sub-protocol. - annotations = getattr(base, '__annotations__', {}) - if (isinstance(annotations, collections.abc.Mapping) and - attr in annotations and - issubclass(other, Generic) and getattr(other, '_is_protocol', False)): - break - else: - return NotImplemented - return True - if '__subclasshook__' not in cls.__dict__: cls.__subclasshook__ = _proto_hook - # We have nothing more to do for non-protocols... - if not cls._is_protocol: - return - - # ... otherwise prohibit instantiation. - if cls.__init__ is Protocol.__init__: + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: cls.__init__ = _no_init_or_replace_init diff --git a/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst b/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst new file mode 100644 index 00000000000000..982192e59e3a50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-21-19-04-27.gh-issue-105974.M47n3t.rst @@ -0,0 +1,6 @@ +Fix bug where a :class:`typing.Protocol` class that had one or more +non-callable members would raise :exc:`TypeError` when :func:`issubclass` +was called against it, even if it defined a custom ``__subclasshook__`` +method. The behaviour in Python 3.11 and lower -- which has now been +restored -- was not to raise :exc:`TypeError` in these situations if a +custom ``__subclasshook__`` method was defined. Patch by Alex Waygood. From c8c162ef5294cddb7ac75fe93ab918e5661c68ee Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 23 Jun 2023 19:53:27 +0300 Subject: [PATCH 126/446] gh-106030: Miscellaneous fixes in Python/suggestions.c (GH-106031) * PyDict_GetItem() and PyObject_HasAttr() suppress arbitrary errors and should not be used. * PyUnicode_CompareWithASCIIString() only works if the second argument is ASCII string. * Refleak in get_suggestions_for_name_error. * Use of borrowed pointer after possible freeing (self). * Add some missing error checks. --- Python/suggestions.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/Python/suggestions.c b/Python/suggestions.c index f2c018ef2c4533..ad58393490efc2 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -151,15 +151,15 @@ calculate_suggestions(PyObject *dir, } for (int i = 0; i < dir_size; ++i) { PyObject *item = PyList_GET_ITEM(dir, i); + if (_PyUnicode_Equal(name, item)) { + continue; + } Py_ssize_t item_size; const char *item_str = PyUnicode_AsUTF8AndSize(item, &item_size); if (item_str == NULL) { PyMem_Free(buffer); return NULL; } - if (PyUnicode_CompareWithASCIIString(name, item_str) == 0) { - continue; - } // No more than 1/3 of the involved characters should need changed. Py_ssize_t max_distance = (name_size + item_size + 3) * MOVE_COST / 6; // Don't take matches we've already beaten. @@ -220,37 +220,48 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) assert(code != NULL && code->co_localsplusnames != NULL); PyObject *varnames = _PyCode_GetVarnames(code); + Py_DECREF(code); if (varnames == NULL) { return NULL; } PyObject *dir = PySequence_List(varnames); Py_DECREF(varnames); - Py_DECREF(code); if (dir == NULL) { return NULL; } // Are we inside a method and the instance has an attribute called 'name'? - if (PySequence_Contains(dir, &_Py_ID(self)) > 0) { + int res = PySequence_Contains(dir, &_Py_ID(self)); + if (res < 0) { + goto error; + } + if (res > 0) { PyObject* locals = PyFrame_GetLocals(frame); if (!locals) { goto error; } - PyObject* self = PyDict_GetItem(locals, &_Py_ID(self)); /* borrowed */ - Py_DECREF(locals); + PyObject* self = PyDict_GetItemWithError(locals, &_Py_ID(self)); /* borrowed */ if (!self) { + Py_DECREF(locals); goto error; } - if (PyObject_HasAttr(self, name)) { + PyObject *value; + res = _PyObject_LookupAttr(self, name, &value); + Py_DECREF(locals); + if (res < 0) { + goto error; + } + if (value) { + Py_DECREF(value); Py_DECREF(dir); - return PyUnicode_FromFormat("self.%S", name); + return PyUnicode_FromFormat("self.%U", name); } } PyObject *suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); - if (suggestions != NULL) { + if (suggestions != NULL || PyErr_Occurred()) { return suggestions; } @@ -260,7 +271,7 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) } suggestions = calculate_suggestions(dir, name); Py_DECREF(dir); - if (suggestions != NULL) { + if (suggestions != NULL || PyErr_Occurred()) { return suggestions; } @@ -319,15 +330,16 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) assert(frame != NULL); PyObject* suggestion = get_suggestions_for_name_error(name, frame); - bool is_stdlib_module = is_name_stdlib_module(name); - - if (suggestion == NULL && !is_stdlib_module) { + if (suggestion == NULL && PyErr_Occurred()) { return NULL; } // Add a trailer ". Did you mean: (...)?" PyObject* result = NULL; - if (!is_stdlib_module) { + if (!is_name_stdlib_module(name)) { + if (suggestion == NULL) { + return NULL; + } result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion); } else if (suggestion == NULL) { result = PyUnicode_FromFormat(". Did you forget to import %R?", name); From 41ad4dfc04c201728ce9fa12b1a96922dd15a368 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 23 Jun 2023 19:04:17 +0200 Subject: [PATCH 127/446] gh-105063: Disable test_peg_generator.TestCParser bco. ref leaks (#106024) Since gh-104798 (Use setuptools in peg-generator and reenable tests), the TestCParser test case has been producing ref leaks. --- Lib/test/test_peg_generator/test_c_parser.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index af39faeba94357..f9105a9f23bd6d 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -74,8 +74,18 @@ def test_parse(self): @support.requires_subprocess() class TestCParser(unittest.TestCase): + _has_run = False + @classmethod def setUpClass(cls): + if cls._has_run: + # Since gh-104798 (Use setuptools in peg-generator and reenable + # tests), this test case has been producing ref leaks. Initial + # debugging points to bug(s) in setuptools and/or importlib. + # See gh-105063 for more info. + raise unittest.SkipTest("gh-105063: can not rerun because of ref. leaks") + cls._has_run = True + # When running under regtest, a separate tempdir is used # as the current directory and watched for left-overs. # Reusing that as the base for temporary directories From 1d33d5378058671bfabb6f4d4b5bfd4726973ff9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 23 Jun 2023 20:10:32 +0300 Subject: [PATCH 128/446] gh-106033: Get rid of new occurrences of PyDict_GetItem and PyObject_HasAttr (GH-106034) These functions are broken by design because they discard any exceptions raised inside, including MemoryError and KeyboardInterrupt. They should not be used in new code. --- Modules/_hashopenssl.c | 13 +++++++------ Modules/_testcapi/code.c | 2 +- Objects/exceptions.c | 31 +++++++++++++++---------------- Objects/typeobject.c | 5 ++++- Python/pythonrun.c | 12 +++++------- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index c018a76842be8c..259db809b8664c 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -383,14 +383,15 @@ py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type } else { _hashlibstate *state = get_hashlib_state(module); // borrowed ref - name_obj = PyDict_GetItem(state->constructs, digestmod); + name_obj = PyDict_GetItemWithError(state->constructs, digestmod); } if (name_obj == NULL) { - _hashlibstate *state = get_hashlib_state(module); - PyErr_Clear(); - PyErr_Format( - state->unsupported_digestmod_error, - "Unsupported digestmod %R", digestmod); + if (!PyErr_Occurred()) { + _hashlibstate *state = get_hashlib_state(module); + PyErr_Format( + state->unsupported_digestmod_error, + "Unsupported digestmod %R", digestmod); + } return NULL; } diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c index 84c668cd6b3b00..cadaf5eb94692e 100644 --- a/Modules/_testcapi/code.c +++ b/Modules/_testcapi/code.c @@ -9,7 +9,7 @@ get_code_extra_index(PyInterpreterState* interp) { PyObject *interp_dict = PyInterpreterState_GetDict(interp); // borrowed assert(interp_dict); // real users would handle missing dict... somehow - PyObject *index_obj = PyDict_GetItemString(interp_dict, key); // borrowed + PyObject *index_obj = _PyDict_GetItemStringWithError(interp_dict, key); // borrowed Py_ssize_t index = 0; if (!index_obj) { if (PyErr_Occurred()) { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index e2a3f89b177ff6..04ea22c2902df7 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -207,22 +207,21 @@ BaseException_add_note(PyObject *self, PyObject *note) return NULL; } - if (!PyObject_HasAttr(self, &_Py_ID(__notes__))) { - PyObject *new_notes = PyList_New(0); - if (new_notes == NULL) { + PyObject *notes; + if (_PyObject_LookupAttr(self, &_Py_ID(__notes__), ¬es) < 0) { + return NULL; + } + if (notes == NULL) { + notes = PyList_New(0); + if (notes == NULL) { return NULL; } - if (PyObject_SetAttr(self, &_Py_ID(__notes__), new_notes) < 0) { - Py_DECREF(new_notes); + if (PyObject_SetAttr(self, &_Py_ID(__notes__), notes) < 0) { + Py_DECREF(notes); return NULL; } - Py_DECREF(new_notes); } - PyObject *notes = PyObject_GetAttr(self, &_Py_ID(__notes__)); - if (notes == NULL) { - return NULL; - } - if (!PyList_Check(notes)) { + else if (!PyList_Check(notes)) { Py_DECREF(notes); PyErr_SetString(PyExc_TypeError, "Cannot add note: __notes__ is not a list"); return NULL; @@ -941,11 +940,11 @@ exceptiongroup_subset( PyException_SetContext(eg, PyException_GetContext(orig)); PyException_SetCause(eg, PyException_GetCause(orig)); - if (PyObject_HasAttr(orig, &_Py_ID(__notes__))) { - PyObject *notes = PyObject_GetAttr(orig, &_Py_ID(__notes__)); - if (notes == NULL) { - goto error; - } + PyObject *notes; + if (_PyObject_LookupAttr(orig, &_Py_ID(__notes__), ¬es) < 0) { + goto error; + } + if (notes) { if (PySequence_Check(notes)) { /* Make a copy so the parts have independent notes lists. */ PyObject *notes_copy = PySequence_List(notes); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d427ecd50a76fc..9aba53df157910 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1508,11 +1508,14 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) static PyObject * type_get_type_params(PyTypeObject *type, void *context) { - PyObject *params = PyDict_GetItem(lookup_tp_dict(type), &_Py_ID(__type_params__)); + PyObject *params = PyDict_GetItemWithError(lookup_tp_dict(type), &_Py_ID(__type_params__)); if (params) { return Py_NewRef(params); } + if (PyErr_Occurred()) { + return NULL; + } return PyTuple_New(0); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 2986622a8b0dcf..1ec21440c7abad 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1134,15 +1134,13 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) return 0; } - if (!PyObject_HasAttr(value, &_Py_ID(__notes__))) { - return 0; - } - PyObject *notes = PyObject_GetAttr(value, &_Py_ID(__notes__)); - if (notes == NULL) { - return -1; + PyObject *notes; + int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), ¬es); + if (res <= 0) { + return res; } if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { - int res = 0; + res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; } From d8ca5a11bc55e2a69cab4f8795d0a5aa6932a41b Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 23 Jun 2023 19:47:47 +0100 Subject: [PATCH 129/446] gh-105730: support more callables in ExceptionGroup.split() and subgroup() (#106035) --- Doc/library/exceptions.rst | 12 ++-- Lib/test/test_exception_group.py | 65 +++++++++++++------ ...-06-23-16-51-02.gh-issue-105730.16haMe.rst | 2 + Objects/exceptions.c | 6 +- 4 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-23-16-51-02.gh-issue-105730.16haMe.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 4c84e5f855431a..8e574b8334e445 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -912,10 +912,11 @@ their subgroups based on the types of the contained exceptions. Returns an exception group that contains only the exceptions from the current group that match *condition*, or ``None`` if the result is empty. - The condition can be either a function that accepts an exception and returns - true for those that should be in the subgroup, or it can be an exception type - or a tuple of exception types, which is used to check for a match using the - same check that is used in an ``except`` clause. + The condition can be an exception type or tuple of exception types, in which + case each exception is checked for a match using the same check that is used + in an ``except`` clause. The condition can also be a callable (other than + a type object) that accepts an exception as its single argument and returns + true for the exceptions that should be in the subgroup. The nesting structure of the current exception is preserved in the result, as are the values of its :attr:`message`, :attr:`__traceback__`, @@ -926,6 +927,9 @@ their subgroups based on the types of the contained exceptions. including the top-level and any nested exception groups. If the condition is true for such an exception group, it is included in the result in full. + .. versionadded:: 3.13 + ``condition`` can be any callable which is not a type object. + .. method:: split(condition) Like :meth:`subgroup`, but returns the pair ``(match, rest)`` where ``match`` diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py index fa159a76ec1aff..2658e027ff3e2b 100644 --- a/Lib/test/test_exception_group.py +++ b/Lib/test/test_exception_group.py @@ -294,6 +294,15 @@ def assertMatchesTemplate(self, exc, exc_type, template): self.assertEqual(type(exc), type(template)) self.assertEqual(exc.args, template.args) +class Predicate: + def __init__(self, func): + self.func = func + + def __call__(self, e): + return self.func(e) + + def method(self, e): + return self.func(e) class ExceptionGroupSubgroupTests(ExceptionGroupTestBase): def setUp(self): @@ -301,10 +310,15 @@ def setUp(self): self.eg_template = [ValueError(1), TypeError(int), ValueError(2)] def test_basics_subgroup_split__bad_arg_type(self): + class C: + pass + bad_args = ["bad arg", + C, OSError('instance not type'), [OSError, TypeError], - (OSError, 42)] + (OSError, 42), + ] for arg in bad_args: with self.assertRaises(TypeError): self.eg.subgroup(arg) @@ -336,10 +350,14 @@ def test_basics_subgroup_by_type__match(self): self.assertMatchesTemplate(subeg, ExceptionGroup, template) def test_basics_subgroup_by_predicate__passthrough(self): - self.assertIs(self.eg, self.eg.subgroup(lambda e: True)) + f = lambda e: True + for callable in [f, Predicate(f), Predicate(f).method]: + self.assertIs(self.eg, self.eg.subgroup(callable)) def test_basics_subgroup_by_predicate__no_match(self): - self.assertIsNone(self.eg.subgroup(lambda e: False)) + f = lambda e: False + for callable in [f, Predicate(f), Predicate(f).method]: + self.assertIsNone(self.eg.subgroup(callable)) def test_basics_subgroup_by_predicate__match(self): eg = self.eg @@ -350,9 +368,12 @@ def test_basics_subgroup_by_predicate__match(self): ((ValueError, TypeError), self.eg_template)] for match_type, template in testcases: - subeg = eg.subgroup(lambda e: isinstance(e, match_type)) - self.assertEqual(subeg.message, eg.message) - self.assertMatchesTemplate(subeg, ExceptionGroup, template) + f = lambda e: isinstance(e, match_type) + for callable in [f, Predicate(f), Predicate(f).method]: + with self.subTest(callable=callable): + subeg = eg.subgroup(f) + self.assertEqual(subeg.message, eg.message) + self.assertMatchesTemplate(subeg, ExceptionGroup, template) class ExceptionGroupSplitTests(ExceptionGroupTestBase): @@ -399,14 +420,18 @@ def test_basics_split_by_type__match(self): self.assertIsNone(rest) def test_basics_split_by_predicate__passthrough(self): - match, rest = self.eg.split(lambda e: True) - self.assertMatchesTemplate(match, ExceptionGroup, self.eg_template) - self.assertIsNone(rest) + f = lambda e: True + for callable in [f, Predicate(f), Predicate(f).method]: + match, rest = self.eg.split(callable) + self.assertMatchesTemplate(match, ExceptionGroup, self.eg_template) + self.assertIsNone(rest) def test_basics_split_by_predicate__no_match(self): - match, rest = self.eg.split(lambda e: False) - self.assertIsNone(match) - self.assertMatchesTemplate(rest, ExceptionGroup, self.eg_template) + f = lambda e: False + for callable in [f, Predicate(f), Predicate(f).method]: + match, rest = self.eg.split(callable) + self.assertIsNone(match) + self.assertMatchesTemplate(rest, ExceptionGroup, self.eg_template) def test_basics_split_by_predicate__match(self): eg = self.eg @@ -420,14 +445,16 @@ def test_basics_split_by_predicate__match(self): ] for match_type, match_template, rest_template in testcases: - match, rest = eg.split(lambda e: isinstance(e, match_type)) - self.assertEqual(match.message, eg.message) - self.assertMatchesTemplate( - match, ExceptionGroup, match_template) - if rest_template is not None: - self.assertEqual(rest.message, eg.message) + f = lambda e: isinstance(e, match_type) + for callable in [f, Predicate(f), Predicate(f).method]: + match, rest = eg.split(callable) + self.assertEqual(match.message, eg.message) self.assertMatchesTemplate( - rest, ExceptionGroup, rest_template) + match, ExceptionGroup, match_template) + if rest_template is not None: + self.assertEqual(rest.message, eg.message) + self.assertMatchesTemplate( + rest, ExceptionGroup, rest_template) class DeepRecursionInSplitAndSubgroup(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-23-16-51-02.gh-issue-105730.16haMe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-23-16-51-02.gh-issue-105730.16haMe.rst new file mode 100644 index 00000000000000..fa70ee09ce27a1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-23-16-51-02.gh-issue-105730.16haMe.rst @@ -0,0 +1,2 @@ +Allow any callable other than type objects as the condition predicate in +:meth:`BaseExceptionGroup.split` and :meth:`BaseExceptionGroup.subgroup`. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 04ea22c2902df7..f27e6f6c1431a0 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -992,7 +992,7 @@ get_matcher_type(PyObject *value, { assert(value); - if (PyFunction_Check(value)) { + if (PyCallable_Check(value) && !PyType_Check(value)) { *type = EXCEPTION_GROUP_MATCH_BY_PREDICATE; return 0; } @@ -1016,7 +1016,7 @@ get_matcher_type(PyObject *value, error: PyErr_SetString( PyExc_TypeError, - "expected a function, exception type or tuple of exception types"); + "expected an exception type, a tuple of exception types, or a callable (other than a class)"); return -1; } @@ -1032,7 +1032,7 @@ exceptiongroup_split_check_match(PyObject *exc, return PyErr_GivenExceptionMatches(exc, matcher_value); } case EXCEPTION_GROUP_MATCH_BY_PREDICATE: { - assert(PyFunction_Check(matcher_value)); + assert(PyCallable_Check(matcher_value) && !PyType_Check(matcher_value)); PyObject *exc_matches = PyObject_CallOneArg(matcher_value, exc); if (exc_matches == NULL) { return -1; From 8ef0ee4ebc84ee68f16cea85ffdb949ecccb4ba5 Mon Sep 17 00:00:00 2001 From: Eamon Tracey <66919574+EamonTracey@users.noreply.github.com> Date: Fri, 23 Jun 2023 16:34:05 -0400 Subject: [PATCH 130/446] Typing docs: fix typo in annotating tuples comment (#106048) --- Doc/library/typing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 7458fa568b3253..9771ba0a794b35 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -362,8 +362,8 @@ the container will be of the same type. For example:: # Type checker error: ``list`` only accepts a single type argument: y: list[int, str] = [1, 'foo'] - # Type checker will infer that all keys in ``y`` are meant to be strings, - # and that all values in ``y`` are meant to be either strings or ints + # Type checker will infer that all keys in ``z`` are meant to be strings, + # and that all values in ``z`` are meant to be either strings or ints z: Mapping[str, str | int] = {} :class:`list` only accepts one type argument, so a type checker would emit an From 4849a80dd1cbbc5010e8749ba60eb91a541ae4e7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 24 Jun 2023 01:34:05 +0200 Subject: [PATCH 131/446] gh-102251: Disable non-rerunnable test in test_import (#106013) --- Lib/test/test_import/__init__.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index e0e2354ae2f19f..ec8ccf0bd78d37 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -107,6 +107,25 @@ def remove_files(name): rmtree('__pycache__') +def no_rerun(reason): + """Skip rerunning for a particular test. + + WARNING: Use this decorator with care; skipping rerunning makes it + impossible to find reference leaks. Provide a clear reason for skipping the + test using the 'reason' parameter. + """ + def deco(func): + _has_run = False + def wrapper(self): + nonlocal _has_run + if _has_run: + self.skipTest(reason) + func(self) + _has_run = True + return wrapper + return deco + + @contextlib.contextmanager def _ready_to_import(name=None, source=""): # sets up a temporary directory and removes it @@ -1989,10 +2008,6 @@ class SinglephaseInitTests(unittest.TestCase): @classmethod def setUpClass(cls): - if '-R' in sys.argv or '--huntrleaks' in sys.argv: - # https://github.com/python/cpython/issues/102251 - raise unittest.SkipTest('unresolved refleaks (see gh-102251)') - spec = importlib.util.find_spec(cls.NAME) from importlib.machinery import ExtensionFileLoader cls.FILE = spec.origin @@ -2502,6 +2517,7 @@ def test_basic_multiple_interpreters_main_no_reset(self): # * m_copy was copied from interp2 (was from interp1) # * module's global state was updated, not reset + @no_rerun(reason="rerun not possible; module state is never cleared (see gh-102251)") @requires_subinterpreters def test_basic_multiple_interpreters_deleted_no_reset(self): # without resetting; already loaded in a deleted interpreter From d2cbb6e918d9ea39f0dd44acb53270f2dac07454 Mon Sep 17 00:00:00 2001 From: chgnrdv <52372310+chgnrdv@users.noreply.github.com> Date: Sat, 24 Jun 2023 08:23:24 +0300 Subject: [PATCH 132/446] gh-105987: Fix reference counting issue in `_asyncio._swap_current_task` (#105989) --- .../test_asyncio/test_eager_task_factory.py | 19 +++++++++++++++++++ ...-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst | 1 + Modules/_asynciomodule.c | 11 +++++++---- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py b/Lib/test/test_asyncio/test_eager_task_factory.py index 49d5dbb8940a96..fc9ad8eb43bb1b 100644 --- a/Lib/test/test_asyncio/test_eager_task_factory.py +++ b/Lib/test/test_asyncio/test_eager_task_factory.py @@ -7,6 +7,8 @@ from unittest import mock from asyncio import tasks from test.test_asyncio import utils as test_utils +import test.support +from test.support.script_helper import assert_python_ok MOCK_ANY = mock.ANY @@ -222,6 +224,23 @@ class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase): Task = getattr(tasks, '_CTask', None) + def test_issue105987(self): + code = """if 1: + from _asyncio import _swap_current_task + + class DummyTask: + pass + + class DummyLoop: + pass + + l = DummyLoop() + _swap_current_task(l, DummyTask()) + t = _swap_current_task(l, None) + """ + + _, out, err = assert_python_ok("-c", code) + self.assertFalse(err) class AsyncTaskCounter: def __init__(self, loop, *, task_class, eager): diff --git a/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst new file mode 100644 index 00000000000000..0bc97da4edf0f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst @@ -0,0 +1 @@ +Fix crash due to improper reference counting in :mod:`asyncio` eager task factory internal routines. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 4b84c1de66be0e..5b28f2dd28a221 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -2047,20 +2047,23 @@ swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task) } prev_task = Py_None; } + Py_INCREF(prev_task); if (task == Py_None) { if (_PyDict_DelItem_KnownHash(state->current_tasks, loop, hash) == -1) { - return NULL; + goto error; } } else { if (_PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash) == -1) { - return NULL; + goto error; } } - Py_INCREF(prev_task); - return prev_task; + +error: + Py_DECREF(prev_task); + return NULL; } /* ----- Task */ From 4a6c84fc1ea8f26d84a0fbeeff6f8dedc32263d4 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 24 Jun 2023 16:14:09 +0100 Subject: [PATCH 133/446] GH-104375: Use `versionchanged` to describe new arguments in pathlib docs (GH-104376) --- Doc/library/pathlib.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 3a4e1e64685cb4..9bbfe384ce54c4 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -596,8 +596,8 @@ Pure paths provide the following methods and properties: Set *case_sensitive* to ``True`` or ``False`` to override this behaviour. - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. .. versionchanged:: 3.13 Support for the recursive wildcard "``**``" was added. In previous @@ -642,8 +642,8 @@ Pure paths provide the following methods and properties: are present in the path; call :meth:`~Path.resolve` first if necessary to resolve symlinks. - .. versionadded:: 3.12 - The *walk_up* argument (old behavior is the same as ``walk_up=False``). + .. versionchanged:: 3.12 + The *walk_up* parameter was added (old behavior is the same as ``walk_up=False``). .. deprecated-removed:: 3.12 3.14 @@ -962,11 +962,11 @@ call fails (for example because the path doesn't exist). Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. - .. versionadded:: 3.13 - The *follow_symlinks* argument. + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. .. method:: Path.group() @@ -1362,8 +1362,8 @@ call fails (for example because the path doesn't exist). infinite loop is encountered along the resolution path, :exc:`RuntimeError` is raised. - .. versionadded:: 3.6 - The *strict* argument (pre-3.6 behavior is strict). + .. versionchanged:: 3.6 + The *strict* parameter was added (pre-3.6 behavior is strict). .. method:: Path.rglob(pattern, *, case_sensitive=None, follow_symlinks=None) @@ -1394,11 +1394,11 @@ call fails (for example because the path doesn't exist). Return only directories if *pattern* ends with a pathname components separator (:data:`~os.sep` or :data:`~os.altsep`). - .. versionadded:: 3.12 - The *case_sensitive* argument. + .. versionchanged:: 3.12 + The *case_sensitive* parameter was added. - .. versionadded:: 3.13 - The *follow_symlinks* argument. + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. .. method:: Path.rmdir() From 19d6511b0b8f3f74e668ae32ccef89bcbf1a8a62 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 24 Jun 2023 16:29:26 -0700 Subject: [PATCH 134/446] gh-106033: [docs] Improve C API GetItem & HasAttr notes. (#106047) Use a note:: tag so that these dict and object API deficiencies show up clearly. A caution:: tag was considered, but our current python docs rendering doesn't do much with that (no box or color change). warning:: seemed too extreme. note looks good. --- Doc/c-api/dict.rst | 19 ++++++++++++------- Doc/c-api/object.rst | 18 +++++++++++------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 0ca8ad624b2034..bd0c36a217e2ce 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -98,9 +98,11 @@ Dictionary Objects Return the object from dictionary *p* which has a key *key*. Return ``NULL`` if the key *key* is not present, but *without* setting an exception. - Note that exceptions which occur while calling :meth:`__hash__` and - :meth:`__eq__` methods will get suppressed. - To get error reporting use :c:func:`PyDict_GetItemWithError()` instead. + .. note:: + + Exceptions that occur while this calls :meth:`~object.__hash__` and + :meth:`~object.__eq__` methods are silently ignored. + Prefer the :c:func:`PyDict_GetItemWithError` function instead. .. versionchanged:: 3.10 Calling this API without :term:`GIL` held had been allowed for historical @@ -120,10 +122,13 @@ Dictionary Objects This is the same as :c:func:`PyDict_GetItem`, but *key* is specified as a :c:expr:`const char*`, rather than a :c:expr:`PyObject*`. - Note that exceptions which occur while calling :meth:`__hash__` and - :meth:`__eq__` methods and creating a temporary string object - will get suppressed. - To get error reporting use :c:func:`PyDict_GetItemWithError()` instead. + .. note:: + + Exceptions that occur while this calls :meth:`~object.__hash__` and + :meth:`~object.__eq__` methods or while creating the temporary :class:`str` + object are silently ignored. + Prefer using the :c:func:`PyDict_GetItemWithError` function with your own + :c:func:`PyUnicode_FromString` *key* instead. .. c:function:: PyObject* PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index a25ff244c9f07c..22e7458013fb3d 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -33,9 +33,11 @@ Object Protocol is equivalent to the Python expression ``hasattr(o, attr_name)``. This function always succeeds. - Note that exceptions which occur while calling :meth:`__getattr__` and - :meth:`__getattribute__` methods will get suppressed. - To get error reporting use :c:func:`PyObject_GetAttr()` instead. + .. note:: + + Exceptions that occur when this calls :meth:`~object.__getattr__` and + :meth:`~object.__getattribute__` methods are silently ignored. + For proper error handling, use :c:func:`PyObject_GetAttr` instead. .. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name) @@ -44,10 +46,12 @@ Object Protocol is equivalent to the Python expression ``hasattr(o, attr_name)``. This function always succeeds. - Note that exceptions which occur while calling :meth:`__getattr__` and - :meth:`__getattribute__` methods and creating a temporary string object - will get suppressed. - To get error reporting use :c:func:`PyObject_GetAttrString()` instead. + .. note:: + + Exceptions that occur when this calls :meth:`~object.__getattr__` and + :meth:`~object.__getattribute__` methods or while creating the temporary :class:`str` + object are silently ignored. + For proper error handling, use :c:func:`PyObject_GetAttrString` instead. .. c:function:: PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name) From bef1c8761e3b0dfc5708747bb646ad8b669cbd67 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 25 Jun 2023 02:02:59 +0200 Subject: [PATCH 135/446] Docs: add links to 'callable' term in sqlite3 docs (#106072) --- Doc/library/sqlite3.rst | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 7544b88216e73c..bc69387fca8a93 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -413,15 +413,15 @@ Module functions .. function:: register_adapter(type, adapter, /) - Register an *adapter* callable to adapt the Python type *type* into an - SQLite type. + Register an *adapter* :term:`callable` to adapt the Python type *type* + into an SQLite type. The adapter is called with a Python object of type *type* as its sole argument, and must return a value of a :ref:`type that SQLite natively understands `. .. function:: register_converter(typename, converter, /) - Register the *converter* callable to convert SQLite objects of type + Register the *converter* :term:`callable` to convert SQLite objects of type *typename* into a Python object of a specific type. The converter is invoked for all SQLite values of type *typename*; it is passed a :class:`bytes` object and should return an object of the @@ -484,7 +484,7 @@ Module constants SQLITE_DENY SQLITE_IGNORE - Flags that should be returned by the *authorizer_callback* callable + Flags that should be returned by the *authorizer_callback* :term:`callable` passed to :meth:`Connection.set_authorizer`, to indicate whether: * Access is allowed (:const:`!SQLITE_OK`), @@ -629,8 +629,8 @@ Connection objects Create and return a :class:`Cursor` object. The cursor method accepts a single optional parameter *factory*. If - supplied, this must be a callable returning an instance of :class:`Cursor` - or its subclasses. + supplied, this must be a :term:`callable` returning + an instance of :class:`Cursor` or its subclasses. .. method:: blobopen(table, column, row, /, *, readonly=False, name="main") @@ -723,7 +723,7 @@ Connection objects If ``-1``, it may take any number of arguments. :param func: - A callable that is called when the SQL function is invoked. + A :term:`callable` that is called when the SQL function is invoked. The callable must return :ref:`a type natively supported by SQLite `. Set to ``None`` to remove an existing SQL function. @@ -945,9 +945,10 @@ Connection objects .. method:: set_authorizer(authorizer_callback) - Register callable *authorizer_callback* to be invoked for each attempt to - access a column of a table in the database. The callback should return - one of :const:`SQLITE_OK`, :const:`SQLITE_DENY`, or :const:`SQLITE_IGNORE` + Register :term:`callable` *authorizer_callback* to be invoked + for each attempt to access a column of a table in the database. + The callback should return one of :const:`SQLITE_OK`, + :const:`SQLITE_DENY`, or :const:`SQLITE_IGNORE` to signal how access to the column should be handled by the underlying SQLite library. @@ -970,7 +971,7 @@ Connection objects .. method:: set_progress_handler(progress_handler, n) - Register callable *progress_handler* to be invoked for every *n* + Register :term:`callable` *progress_handler* to be invoked for every *n* instructions of the SQLite virtual machine. This is useful if you want to get called from SQLite during long-running operations, for example to update a GUI. @@ -985,8 +986,8 @@ Connection objects .. method:: set_trace_callback(trace_callback) - Register callable *trace_callback* to be invoked for each SQL statement - that is actually executed by the SQLite backend. + Register :term:`callable` *trace_callback* to be invoked + for each SQL statement that is actually executed by the SQLite backend. The only argument passed to the callback is the statement (as :class:`str`) that is being executed. The return value of the callback is @@ -1136,8 +1137,8 @@ Connection objects Defaults to ``-1``. :param progress: - If set to a callable, it is invoked with three integer arguments for - every backup iteration: + If set to a :term:`callable`, + it is invoked with three integer arguments for every backup iteration: the *status* of the last iteration, the *remaining* number of pages still to be copied, and the *total* number of pages. @@ -1401,8 +1402,8 @@ Connection objects .. attribute:: text_factory - A callable that accepts a :class:`bytes` parameter and returns a text - representation of it. + A :term:`callable` that accepts a :class:`bytes` parameter + and returns a text representation of it. The callable is invoked for SQLite values with the ``TEXT`` data type. By default, this attribute is set to :class:`str`. If you want to return ``bytes`` instead, set *text_factory* to ``bytes``. From 8c24a837371439b8e922ff47275085b581f510c5 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 25 Jun 2023 13:44:23 +0300 Subject: [PATCH 136/446] Add end-of-file-fixer to pre-commit (#106065) --- .pre-commit-config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 464bcde6e98424..d62c57c044728f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,6 +3,9 @@ repos: rev: v4.4.0 hooks: - id: check-yaml + - id: end-of-file-fixer + types: [python] + exclude: Lib/test/coding20731.py - id: trailing-whitespace types_or: [c, python, rst] From 93a970ffbce58657cc99305be69e460a11371730 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 26 Jun 2023 00:06:12 +0100 Subject: [PATCH 137/446] gh-106046: Improve error message from `os.fspath` if `__fspath__` is set to `None` (#106082) --- Doc/reference/datamodel.rst | 5 ++- Lib/os.py | 6 +++ Lib/test/test_os.py | 39 +++++++++++++++++++ ...-06-23-22-52-24.gh-issue-106046.OdLiLJ.rst | 2 + Modules/posixmodule.c | 4 +- 5 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-23-22-52-24.gh-issue-106046.OdLiLJ.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e8f9775dd33ce1..7f5edbbcadca6c 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -3179,8 +3179,9 @@ An example of an asynchronous context manager class:: lead to some very strange behaviour if it is handled incorrectly. .. [#] The :meth:`~object.__hash__`, :meth:`~object.__iter__`, - :meth:`~object.__reversed__`, and :meth:`~object.__contains__` methods have - special handling for this; others + :meth:`~object.__reversed__`, :meth:`~object.__contains__`, + :meth:`~object.__class_getitem__` and :meth:`~os.PathLike.__fspath__` + methods have special handling for this. Others will still raise a :exc:`TypeError`, but may do so by relying on the behavior that ``None`` is not callable. diff --git a/Lib/os.py b/Lib/os.py index 31b957f13215d5..d8c9ba4b15400a 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -1061,6 +1061,12 @@ def _fspath(path): else: raise TypeError("expected str, bytes or os.PathLike object, " "not " + path_type.__name__) + except TypeError: + if path_type.__fspath__ is None: + raise TypeError("expected str, bytes or os.PathLike object, " + "not " + path_type.__name__) from None + else: + raise if isinstance(path_repr, (str, bytes)): return path_repr else: diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 8de4ef7270b754..99e9ed213e5615 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -4647,6 +4647,45 @@ def __fspath__(self): return '' self.assertFalse(hasattr(A(), '__dict__')) + def test_fspath_set_to_None(self): + class Foo: + __fspath__ = None + + class Bar: + def __fspath__(self): + return 'bar' + + class Baz(Bar): + __fspath__ = None + + good_error_msg = ( + r"expected str, bytes or os.PathLike object, not {}".format + ) + + with self.assertRaisesRegex(TypeError, good_error_msg("Foo")): + self.fspath(Foo()) + + self.assertEqual(self.fspath(Bar()), 'bar') + + with self.assertRaisesRegex(TypeError, good_error_msg("Baz")): + self.fspath(Baz()) + + with self.assertRaisesRegex(TypeError, good_error_msg("Foo")): + open(Foo()) + + with self.assertRaisesRegex(TypeError, good_error_msg("Baz")): + open(Baz()) + + other_good_error_msg = ( + r"should be string, bytes or os.PathLike, not {}".format + ) + + with self.assertRaisesRegex(TypeError, other_good_error_msg("Foo")): + os.rename(Foo(), "foooo") + + with self.assertRaisesRegex(TypeError, other_good_error_msg("Baz")): + os.rename(Baz(), "bazzz") + class TimesTests(unittest.TestCase): def test_times(self): times = os.times() diff --git a/Misc/NEWS.d/next/Library/2023-06-23-22-52-24.gh-issue-106046.OdLiLJ.rst b/Misc/NEWS.d/next/Library/2023-06-23-22-52-24.gh-issue-106046.OdLiLJ.rst new file mode 100644 index 00000000000000..ce10a9d81dc64c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-23-22-52-24.gh-issue-106046.OdLiLJ.rst @@ -0,0 +1,2 @@ +Improve the error message from :func:`os.fspath` if called on an object +where ``__fspath__`` is set to ``None``. Patch by Alex Waygood. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 694cff19d2286c..d73886f14cb9ec 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1197,7 +1197,7 @@ path_converter(PyObject *o, void *p) PyObject *func, *res; func = _PyObject_LookupSpecial(o, &_Py_ID(__fspath__)); - if (NULL == func) { + if ((NULL == func) || (func == Py_None)) { goto error_format; } res = _PyObject_CallNoArgs(func); @@ -15430,7 +15430,7 @@ PyOS_FSPath(PyObject *path) } func = _PyObject_LookupSpecial(path, &_Py_ID(__fspath__)); - if (NULL == func) { + if ((NULL == func) || (func == Py_None)) { return PyErr_Format(PyExc_TypeError, "expected str, bytes or os.PathLike object, " "not %.200s", From 00e75a33728cdad7c10088acc36bc55b2f4a0efe Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 08:08:12 +0200 Subject: [PATCH 138/446] gh-106084: Remove old PyObject call aliases (#106085) Remove old aliases which were kept backwards compatibility with Python 3.8: * _PyObject_CallMethodNoArgs() * _PyObject_CallMethodOneArg() * _PyObject_CallOneArg() * _PyObject_FastCallDict() * _PyObject_Vectorcall() * _PyObject_VectorcallMethod() * _PyVectorcall_Function() Update code which used these aliases to use new names. --- Doc/whatsnew/3.13.rst | 14 ++++++++++++++ Include/cpython/abstract.h | 9 --------- .../2023-06-25-18-01-27.gh-issue-106084.PEzqU3.rst | 13 +++++++++++++ Modules/_functoolsmodule.c | 2 +- Modules/cjkcodecs/multibytecodec.c | 4 ++-- Objects/call.c | 4 ++-- Objects/descrobject.c | 6 +++--- Python/errors.c | 2 +- Python/import.c | 4 ++-- Python/marshal.c | 2 +- Python/pythonrun.c | 4 ++-- Python/sysmodule.c | 2 +- 12 files changed, 42 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-25-18-01-27.gh-issue-106084.PEzqU3.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index d1f13a50335b5b..ee8c198734076d 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -568,3 +568,17 @@ Removed `_ can be used to get this function on Python 3.8 and older. (Contributed by Victor Stinner in :gh:`105268`.) + +* Remove the old aliases to functions calling functions which were kept for + backward compatibility with Python 3.8 provisional API: + + * ``_PyObject_CallMethodNoArgs()``: use ``PyObject_CallMethodNoArgs()`` + * ``_PyObject_CallMethodOneArg()``: use ``PyObject_CallMethodOneArg()`` + * ``_PyObject_CallOneArg()``: use ``PyObject_CallOneArg()`` + * ``_PyObject_FastCallDict()``: use ``PyObject_VectorcallDict()`` + * ``_PyObject_Vectorcall()``: use ``PyObject_Vectorcall()`` + * ``_PyObject_VectorcallMethod()``: use ``PyObject_VectorcallMethod()`` + * ``_PyVectorcall_Function()``: use ``PyVectorcall_Function()`` + + Just remove the underscore prefix to update your code. + (Contributed by Victor Stinner in :gh:`106084`.) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 992dd068db90ea..abae3e4f72e97a 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -58,15 +58,6 @@ _PyVectorcall_NARGS(size_t n) PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable); -// Backwards compatibility aliases for API that was provisional in Python 3.8 -#define _PyObject_Vectorcall PyObject_Vectorcall -#define _PyObject_VectorcallMethod PyObject_VectorcallMethod -#define _PyObject_FastCallDict PyObject_VectorcallDict -#define _PyVectorcall_Function PyVectorcall_Function -#define _PyObject_CallOneArg PyObject_CallOneArg -#define _PyObject_CallMethodNoArgs PyObject_CallMethodNoArgs -#define _PyObject_CallMethodOneArg PyObject_CallMethodOneArg - /* Same as PyObject_Vectorcall except that keyword arguments are passed as dict, which may be NULL if there are no keyword arguments. */ PyAPI_FUNC(PyObject *) PyObject_VectorcallDict( diff --git a/Misc/NEWS.d/next/C API/2023-06-25-18-01-27.gh-issue-106084.PEzqU3.rst b/Misc/NEWS.d/next/C API/2023-06-25-18-01-27.gh-issue-106084.PEzqU3.rst new file mode 100644 index 00000000000000..b430f5f7ae0116 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-25-18-01-27.gh-issue-106084.PEzqU3.rst @@ -0,0 +1,13 @@ +Remove the old aliases to functions calling functions which were kept for +backward compatibility with Python 3.8 provisional API: + +* ``_PyObject_CallMethodNoArgs()``: use ``PyObject_CallMethodNoArgs()`` +* ``_PyObject_CallMethodOneArg()``: use ``PyObject_CallMethodOneArg()`` +* ``_PyObject_CallOneArg()``: use ``PyObject_CallOneArg()`` +* ``_PyObject_FastCallDict()``: use ``PyObject_VectorcallDict()`` +* ``_PyObject_Vectorcall()``: use ``PyObject_Vectorcall()`` +* ``_PyObject_VectorcallMethod()``: use ``PyObject_VectorcallMethod()`` +* ``_PyVectorcall_Function()``: use ``PyVectorcall_Function()`` + +Just remove the underscore prefix to update your code. Patch by Victor +Stinner. diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index a8001d71223fdc..aa566c31cc1eaa 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -276,7 +276,7 @@ partial_vectorcall(partialobject *pto, PyObject *const *args, static void partial_setvectorcall(partialobject *pto) { - if (_PyVectorcall_Function(pto->fn) == NULL) { + if (PyVectorcall_Function(pto->fn) == NULL) { /* Don't use vectorcall if the underlying function doesn't support it */ pto->vectorcall = NULL; } diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 2b98bb5ae58bc6..1070a751ffe638 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -1715,7 +1715,7 @@ mbstreamwriter_iwrite(MultibyteStreamWriterObject *self, if (str == NULL) return -1; - wr = _PyObject_CallMethodOneArg(self->stream, str_write, str); + wr = PyObject_CallMethodOneArg(self->stream, str_write, str); Py_DECREF(str); if (wr == NULL) return -1; @@ -1826,7 +1826,7 @@ _multibytecodec_MultibyteStreamWriter_reset_impl(MultibyteStreamWriterObject *se if (PyBytes_Size(pwrt) > 0) { PyObject *wr; - wr = _PyObject_CallMethodOneArg(self->stream, state->str_write, pwrt); + wr = PyObject_CallMethodOneArg(self->stream, state->str_write, pwrt); if (wr == NULL) { Py_DECREF(pwrt); return NULL; diff --git a/Objects/call.c b/Objects/call.c index 40eccefb4a6c8d..fc8a6f9e0a0228 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -122,7 +122,7 @@ _PyObject_FastCallDictTstate(PyThreadState *tstate, PyObject *callable, assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - vectorcallfunc func = _PyVectorcall_Function(callable); + vectorcallfunc func = PyVectorcall_Function(callable); if (func == NULL) { /* Use tp_call instead */ return _PyObject_MakeTpCall(tstate, callable, args, nargs, kwargs); @@ -349,7 +349,7 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable, assert(PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, callable); - vectorcallfunc vector_func = _PyVectorcall_Function(callable); + vectorcallfunc vector_func = PyVectorcall_Function(callable); if (vector_func != NULL) { return _PyVectorcall_Call(tstate, vector_func, callable, args, kwargs); } diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 72ac4703949262..98d8698fa70fbc 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1110,9 +1110,9 @@ mappingproxy_get(mappingproxyobject *pp, PyObject *const *args, Py_ssize_t nargs { return NULL; } - return _PyObject_VectorcallMethod(&_Py_ID(get), newargs, - 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, - NULL); + return PyObject_VectorcallMethod(&_Py_ID(get), newargs, + 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); } static PyObject * diff --git a/Python/errors.c b/Python/errors.c index eab6503046b5cc..b1a9858d82f7d6 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1485,7 +1485,7 @@ write_unraisable_exc_file(PyThreadState *tstate, PyObject *exc_type, } /* Explicitly call file.flush() */ - PyObject *res = _PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); + PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (!res) { return -1; } diff --git a/Python/import.c b/Python/import.c index 97da8bba8adff9..b3699bdec994d6 100644 --- a/Python/import.c +++ b/Python/import.c @@ -278,7 +278,7 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n Py_XDECREF(spec); if (busy) { /* Wait until module is done importing. */ - PyObject *value = _PyObject_CallMethodOneArg( + PyObject *value = PyObject_CallMethodOneArg( IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name); if (value == NULL) { return -1; @@ -1660,7 +1660,7 @@ PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, external= PyObject_GetAttrString(IMPORTLIB(interp), "_bootstrap_external"); if (external != NULL) { - pathobj = _PyObject_CallMethodOneArg( + pathobj = PyObject_CallMethodOneArg( external, &_Py_ID(_get_sourcefile), cpathobj); Py_DECREF(external); } diff --git a/Python/marshal.c b/Python/marshal.c index 352976b1d69f04..972a13876e626b 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1707,7 +1707,7 @@ marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, s = PyMarshal_WriteObjectToString(value, version); if (s == NULL) return NULL; - res = _PyObject_CallMethodOneArg(file, &_Py_ID(write), s); + res = PyObject_CallMethodOneArg(file, &_Py_ID(write), s); Py_DECREF(s); return res; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 1ec21440c7abad..26e474a3efefd1 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1565,7 +1565,7 @@ _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) Py_XDECREF(ctx.seen); /* Call file.flush() */ - PyObject *res = _PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); + PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (!res) { /* Silently ignore file.flush() error */ PyErr_Clear(); @@ -1677,7 +1677,7 @@ flush_io_stream(PyThreadState *tstate, PyObject *name) { PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { - PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); + PyObject *r = PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); if (r) { Py_DECREF(r); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index f5d4711b0c2c92..3284e14e7742db 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3756,7 +3756,7 @@ sys_pyfile_write_unicode(PyObject *unicode, PyObject *file) if (file == NULL) return -1; assert(unicode != NULL); - PyObject *result = _PyObject_CallMethodOneArg(file, &_Py_ID(write), unicode); + PyObject *result = PyObject_CallMethodOneArg(file, &_Py_ID(write), unicode); if (result == NULL) { return -1; } From 7ca871634e7ae8b9c295df5c2154338d2dac1e69 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 08:30:59 +0200 Subject: [PATCH 139/446] gh-106084: Remove _PySequence_BytesToCharpArray() function (#106088) Remove private _PySequence_BytesToCharpArray() and _Py_FreeCharPArray() functions from the public C API: move these functions from Objects/abstract.c to Modules/_posixsubprocess.c. --- Include/cpython/abstract.h | 4 -- Modules/_posixsubprocess.c | 82 ++++++++++++++++++++++++++++++++++++++ Objects/abstract.c | 77 ----------------------------------- 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index abae3e4f72e97a..5d2d2afdd4e751 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -171,10 +171,6 @@ PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); -PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); - -PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); - /* For internal use by buffer API functions */ PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape); diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 2d88f5e9ba1601..52e1d2faf3e9fa 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -182,6 +182,88 @@ _is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence, return 0; } + +// Forward declaration +static void _Py_FreeCharPArray(char *const array[]); + +/* + * Flatten a sequence of bytes() objects into a C array of + * NULL terminated string pointers with a NULL char* terminating the array. + * (ie: an argv or env list) + * + * Memory allocated for the returned list is allocated using PyMem_Malloc() + * and MUST be freed by _Py_FreeCharPArray(). + */ +static char *const * +_PySequence_BytesToCharpArray(PyObject* self) +{ + char **array; + Py_ssize_t i, argc; + PyObject *item = NULL; + Py_ssize_t size; + + argc = PySequence_Size(self); + if (argc == -1) + return NULL; + + assert(argc >= 0); + + if ((size_t)argc > (PY_SSIZE_T_MAX-sizeof(char *)) / sizeof(char *)) { + PyErr_NoMemory(); + return NULL; + } + + array = PyMem_Malloc((argc + 1) * sizeof(char *)); + if (array == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; ++i) { + char *data; + item = PySequence_GetItem(self, i); + if (item == NULL) { + /* NULL terminate before freeing. */ + array[i] = NULL; + goto fail; + } + /* check for embedded null bytes */ + if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) { + /* NULL terminate before freeing. */ + array[i] = NULL; + goto fail; + } + size = PyBytes_GET_SIZE(item) + 1; + array[i] = PyMem_Malloc(size); + if (!array[i]) { + PyErr_NoMemory(); + goto fail; + } + memcpy(array[i], data, size); + Py_DECREF(item); + } + array[argc] = NULL; + + return array; + +fail: + Py_XDECREF(item); + _Py_FreeCharPArray(array); + return NULL; +} + + +/* Free's a NULL terminated char** array of C strings. */ +static void +_Py_FreeCharPArray(char *const array[]) +{ + Py_ssize_t i; + for (i = 0; array[i] != NULL; ++i) { + PyMem_Free(array[i]); + } + PyMem_Free((void*)array); +} + + /* * Do all the Python C API calls in the parent process to turn the pass_fds * "py_fds_to_keep" tuple into a C array. The caller owns allocation and diff --git a/Objects/abstract.c b/Objects/abstract.c index 00087bd86624ee..fecdb4e07239a2 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2906,80 +2906,3 @@ PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result) } return PYGEN_ERROR; } - -/* - * Flatten a sequence of bytes() objects into a C array of - * NULL terminated string pointers with a NULL char* terminating the array. - * (ie: an argv or env list) - * - * Memory allocated for the returned list is allocated using PyMem_Malloc() - * and MUST be freed by _Py_FreeCharPArray(). - */ -char *const * -_PySequence_BytesToCharpArray(PyObject* self) -{ - char **array; - Py_ssize_t i, argc; - PyObject *item = NULL; - Py_ssize_t size; - - argc = PySequence_Size(self); - if (argc == -1) - return NULL; - - assert(argc >= 0); - - if ((size_t)argc > (PY_SSIZE_T_MAX-sizeof(char *)) / sizeof(char *)) { - PyErr_NoMemory(); - return NULL; - } - - array = PyMem_Malloc((argc + 1) * sizeof(char *)); - if (array == NULL) { - PyErr_NoMemory(); - return NULL; - } - for (i = 0; i < argc; ++i) { - char *data; - item = PySequence_GetItem(self, i); - if (item == NULL) { - /* NULL terminate before freeing. */ - array[i] = NULL; - goto fail; - } - /* check for embedded null bytes */ - if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) { - /* NULL terminate before freeing. */ - array[i] = NULL; - goto fail; - } - size = PyBytes_GET_SIZE(item) + 1; - array[i] = PyMem_Malloc(size); - if (!array[i]) { - PyErr_NoMemory(); - goto fail; - } - memcpy(array[i], data, size); - Py_DECREF(item); - } - array[argc] = NULL; - - return array; - -fail: - Py_XDECREF(item); - _Py_FreeCharPArray(array); - return NULL; -} - - -/* Free's a NULL terminated char** array of C strings. */ -void -_Py_FreeCharPArray(char *const array[]) -{ - Py_ssize_t i; - for (i = 0; array[i] != NULL; ++i) { - PyMem_Free(array[i]); - } - PyMem_Free((void*)array); -} From 3eeb8c89063d5ac22c0b1d26e4ae2fd12c149650 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 26 Jun 2023 08:13:48 +0100 Subject: [PATCH 140/446] Improve typing docs on the type of class objects (#106081) --- Doc/library/typing.rst | 108 ++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 9771ba0a794b35..7ac1062eb26d7c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -408,6 +408,52 @@ of the same type ``T``, use ``tuple[T, ...]``. To denote an empty tuple, use z = (1, 2, 3) z = () +.. _type-of-class-objects: + +The type of class objects +========================= + +A variable annotated with ``C`` may accept a value of type ``C``. In +contrast, a variable annotated with ``type[C]`` (or +:class:`typing.Type[C] `) may accept values that are classes +themselves -- specifically, it will accept the *class object* of ``C``. For +example:: + + a = 3 # Has type ``int``` + b = int # Has type ``type[int]`` + c = type(a) # Also has type ``type[int]`` + +Note that ``type[C]`` is covariant:: + + class User: ... + class ProUser(User): ... + class TeamUser(User): ... + + def make_new_user(user_class: type[User]) -> User: + # ... + return user_class() + + make_new_user(User) # OK + make_new_user(ProUser) # Also OK: ``type[ProUser]`` is a subtype of ``type[User]`` + make_new_user(TeamUser) # Still fine + make_new_user(User()) # Error: expected ``type[User]`` but got ``User`` + make_new_user(int) # Error: ``type[int]`` is not a subtype of ``type[User]`` + +The only legal parameters for :class:`type` are classes, :data:`Any`, +:ref:`type variables `, and unions of any of these types. +For example:: + + def new_non_team_user(user_class: type[BasicUser | ProUser]): ... + + new_non_team_user(BasicUser) # OK + new_non_team_user(ProUser) # OK + new_non_team_user(TeamUser) # Error: ``type[TeamUser]`` is not a subtype + # of ``type[BasicUser | ProUser]`` + new_non_team_user(User) # Also an error + +``type[Any]`` is equivalent to :class:`type`, which is the root of Python's +:ref:`metaclass hierarchy `. + .. _user-defined-generics: User-defined generic types @@ -1093,55 +1139,6 @@ These can be used as types in annotations. They all support subscription using ``ParamSpec`` and ``Concatenate``). * :class:`ParamSpec` and :class:`Callable`. - -.. class:: Type(Generic[CT_co]) - - Deprecated alias to :class:`type`. - - A variable annotated with ``C`` may accept a value of type ``C``. In - contrast, a variable annotated with ``type[C]`` or ``Type[C]`` may accept values that are - classes themselves -- specifically, it will accept the *class object* of - ``C``. For example:: - - a = 3 # Has type 'int' - b = int # Has type 'Type[int]' - c = type(a) # Also has type 'Type[int]' - - Note that ``Type[C]`` is covariant:: - - class User: ... - class BasicUser(User): ... - class ProUser(User): ... - class TeamUser(User): ... - - # Accepts User, BasicUser, ProUser, TeamUser, ... - def make_new_user(user_class: Type[User]) -> User: - # ... - return user_class() - - The fact that ``Type[C]`` is covariant implies that all subclasses of - ``C`` should implement the same constructor signature and class method - signatures as ``C``. The type checker should flag violations of this, - but should also allow constructor calls in subclasses that match the - constructor calls in the indicated base class. How the type checker is - required to handle this particular case may change in future revisions of - :pep:`484`. - - The only legal parameters for :class:`Type` are classes, :data:`Any`, - :ref:`type variables `, and unions of any of these types. - For example:: - - def new_non_team_user(user_class: Type[BasicUser | ProUser]): ... - - ``Type[Any]`` is equivalent to ``Type`` which in turn is equivalent - to ``type``, which is the root of Python's metaclass hierarchy. - - .. versionadded:: 3.5.2 - - .. deprecated:: 3.9 - :class:`builtins.type ` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - .. data:: Literal Special typing form to define "literal types". @@ -3189,6 +3186,19 @@ Aliases to built-in types :class:`builtins.tuple ` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. class:: Type(Generic[CT_co]) + + Deprecated alias to :class:`type`. + + See :ref:`type-of-class-objects` for details on using :class:`type` or + ``typing.Type`` in type annotations. + + .. versionadded:: 3.5.2 + + .. deprecated:: 3.9 + :class:`builtins.type ` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + .. _corresponding-to-types-in-collections: Aliases to types in :mod:`collections` From a12e8ffb49e05a1d1874389318911ce9685db232 Mon Sep 17 00:00:00 2001 From: James Webber Date: Mon, 26 Jun 2023 03:54:03 -0400 Subject: [PATCH 141/446] gh-106075: add `asyncio.taskgroups.__all__` to `asyncio.__all__` (#106090) Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Lib/asyncio/__init__.py | 1 + Lib/asyncio/taskgroups.py | 2 +- Misc/ACKS | 1 + .../next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst diff --git a/Lib/asyncio/__init__.py b/Lib/asyncio/__init__.py index fed16ec7c67fac..03165a425eb7d2 100644 --- a/Lib/asyncio/__init__.py +++ b/Lib/asyncio/__init__.py @@ -34,6 +34,7 @@ streams.__all__ + subprocess.__all__ + tasks.__all__ + + taskgroups.__all__ + threads.__all__ + timeouts.__all__ + transports.__all__) diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index bf92bbaf0d0058..24238c4f5f998d 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -2,7 +2,7 @@ # license: PSFL. -__all__ = ["TaskGroup"] +__all__ = ("TaskGroup",) from . import events from . import exceptions diff --git a/Misc/ACKS b/Misc/ACKS index be8755637ffa3c..454b63155f013c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1946,6 +1946,7 @@ Colin Watson David Watson Aaron Watters Alex Waygood +James Webber Russel Webber Henrik Weber Leon Weber diff --git a/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst b/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst new file mode 100644 index 00000000000000..d2687154a58594 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-25-12-28-55.gh-issue-106075.W7tMRb.rst @@ -0,0 +1 @@ +Added `asyncio.taskgroups.__all__` to `asyncio.__all__` for export in star imports. From dac3d389e747c6f6ef17e4e2f38731c8ef83eada Mon Sep 17 00:00:00 2001 From: Gabriel Venberg Date: Mon, 26 Jun 2023 04:09:08 -0500 Subject: [PATCH 142/446] gh-104527: zippapp will now avoid appending an archive to itself. (gh-106076) zippapp will now avoid appending an archive to itself. --- Lib/zipapp.py | 2 +- .../next/Library/2023-06-25-06-57-24.gh-issue-104527.TJEUkd.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-25-06-57-24.gh-issue-104527.TJEUkd.rst diff --git a/Lib/zipapp.py b/Lib/zipapp.py index d8ebfcb6c73b0c..03a214efa10a20 100644 --- a/Lib/zipapp.py +++ b/Lib/zipapp.py @@ -138,7 +138,7 @@ def create_archive(source, target=None, interpreter=None, main=None, with zipfile.ZipFile(fd, 'w', compression=compression) as z: for child in sorted(source.rglob('*')): arcname = child.relative_to(source) - if filter is None or filter(arcname): + if filter is None or filter(arcname) and child.resolve() != arcname.resolve(): z.write(child, arcname.as_posix()) if main_py: z.writestr('__main__.py', main_py.encode('utf-8')) diff --git a/Misc/NEWS.d/next/Library/2023-06-25-06-57-24.gh-issue-104527.TJEUkd.rst b/Misc/NEWS.d/next/Library/2023-06-25-06-57-24.gh-issue-104527.TJEUkd.rst new file mode 100644 index 00000000000000..50b845bcde9bbe --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-25-06-57-24.gh-issue-104527.TJEUkd.rst @@ -0,0 +1 @@ +Zipapp will now skip over apending an archive to itself. From c075a1974b0dce9801cb645c77faa8af612b3db5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 12:10:53 +0200 Subject: [PATCH 143/446] gh-105927: Deprecate PyWeakref_GetObject() function (#106006) Deprecate PyWeakref_GetObject() and PyWeakref_GET_OBJECT() functions. --- Doc/c-api/weakref.rst | 6 ++++++ Doc/whatsnew/3.13.rst | 10 +++++++++- Include/cpython/weakrefobject.h | 3 ++- Include/weakrefobject.h | 2 +- .../2023-06-22-00-25-55.gh-issue-105927.GRxZtI.rst | 3 +++ Modules/_testcapimodule.c | 6 ++++++ Objects/weakrefobject.c | 7 ++++++- 7 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-22-00-25-55.gh-issue-105927.GRxZtI.rst diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index 44f4dce9ea0238..04781f78d23462 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -74,11 +74,17 @@ as much as it can. except when it cannot be destroyed before the last usage of the borrowed reference. + .. deprecated-removed:: 3.13 3.15 + Use :c:func:`PyWeakref_GetRef` instead. + .. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref) Similar to :c:func:`PyWeakref_GetObject`, but does no error checking. + .. deprecated-removed:: 3.13 3.15 + Use :c:func:`PyWeakref_GetRef` instead. + .. c:function:: void PyObject_ClearWeakRefs(PyObject *object) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index ee8c198734076d..b6d13a8aac0f0e 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -470,6 +470,14 @@ Deprecated Scheduled for removal in Python 3.15. (Contributed by Victor Stinner in :gh:`105396`.) +* Deprecate the :c:func:`PyWeakref_GetObject` and + :c:func:`PyWeakref_GET_OBJECT` functions, which return a :term:`borrowed + reference`: use the new :c:func:`PyWeakref_GetRef` function instead, it + returns a :term:`strong reference`. The `pythoncapi-compat project + `__ can be used to get + :c:func:`PyWeakref_GetRef` on Python 3.12 and older. + (Contributed by Victor Stinner in :gh:`105927`.) + Removed ------- @@ -565,7 +573,7 @@ Removed * Remove the old private, undocumented and untested ``_PyGC_FINALIZED()`` macro which was kept for backward compatibility with Python 3.8 and older: use :c:func:`PyObject_GC_IsFinalized()` instead. The `pythoncapi-compat project - `_ can be used to get this + `__ can be used to get this function on Python 3.8 and older. (Contributed by Victor Stinner in :gh:`105268`.) diff --git a/Include/cpython/weakrefobject.h b/Include/cpython/weakrefobject.h index 6bf16553814252..1559e2def61260 100644 --- a/Include/cpython/weakrefobject.h +++ b/Include/cpython/weakrefobject.h @@ -32,7 +32,8 @@ struct _PyWeakReference { vectorcallfunc vectorcall; }; -static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) { +Py_DEPRECATED(3.13) static inline PyObject* PyWeakref_GET_OBJECT(PyObject *ref_obj) +{ PyWeakReference *ref; PyObject *obj; assert(PyWeakref_Check(ref_obj)); diff --git a/Include/weakrefobject.h b/Include/weakrefobject.h index 2c69f9e4564ab3..727ba6934bbacb 100644 --- a/Include/weakrefobject.h +++ b/Include/weakrefobject.h @@ -27,7 +27,7 @@ PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, PyObject *callback); PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, PyObject *callback); -PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); +Py_DEPRECATED(3.13) PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); PyAPI_FUNC(int) PyWeakref_GetRef(PyObject *ref, PyObject **pobj); diff --git a/Misc/NEWS.d/next/C API/2023-06-22-00-25-55.gh-issue-105927.GRxZtI.rst b/Misc/NEWS.d/next/C API/2023-06-22-00-25-55.gh-issue-105927.GRxZtI.rst new file mode 100644 index 00000000000000..57982dc75e004a --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-22-00-25-55.gh-issue-105927.GRxZtI.rst @@ -0,0 +1,3 @@ +Deprecate the :c:func:`PyWeakref_GetObject` and +:c:func:`PyWeakref_GET_OBJECT` functions: use the new +:c:func:`PyWeakref_GetRef` function instead. Patch by Victor Stinner. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index d847539f6608dd..dc8acec6c76921 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3375,6 +3375,10 @@ check_pyimport_addmodule(PyObject *self, PyObject *args) static PyObject * test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) { + // Ignore PyWeakref_GetObject() deprecation, we test it on purpose + _Py_COMP_DIAG_PUSH + _Py_COMP_DIAG_IGNORE_DEPR_DECLS + // Create a new heap type, create an instance of this type, and delete the // type. This object supports weak references. PyObject *new_type = PyObject_CallFunction((PyObject*)&PyType_Type, @@ -3463,6 +3467,8 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) Py_DECREF(weakref); Py_RETURN_NONE; + + _Py_COMP_DIAG_POP } diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index c54f663acdb66c..f3f6c86637e9de 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -923,7 +923,12 @@ PyWeakref_GetObject(PyObject *ref) PyErr_BadInternalCall(); return NULL; } - return PyWeakref_GET_OBJECT(ref); + PyObject *obj = _PyWeakref_GET_REF(ref); + if (obj == NULL) { + return Py_None; + } + Py_DECREF(obj); + return obj; // borrowed reference } /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's From 6200aaf2967de420a2d83236008787c9f791561d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 15:02:43 +0200 Subject: [PATCH 144/446] gh-106084: Remove _PyObject_HasLen() function (#106103) Remove _PyObject_HasLen() and _PySequence_IterSearch() functions from the public C API: move them to the internal C API (pycore_abstract.h). No longer export these symbols (in libpython). Remove also unused pycore_initconfig.h include in typeobject.c. --- Include/cpython/abstract.h | 20 -------------------- Include/internal/pycore_abstract.h | 22 ++++++++++++++++++++++ Objects/iterobject.c | 1 + Objects/typeobject.c | 4 ++-- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 5d2d2afdd4e751..cba0f4c3130921 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -133,8 +133,6 @@ _PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL); } -PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); - /* Guess the size of object 'o' using len(o) or o.__length_hint__(). If neither of those return a non-negative value, then return the default value. If one of the calls fails, this function returns -1. */ @@ -147,24 +145,6 @@ PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); #define PySequence_ITEM(o, i)\ ( Py_TYPE(o)->tp_as_sequence->sq_item((o), (i)) ) -#define PY_ITERSEARCH_COUNT 1 -#define PY_ITERSEARCH_INDEX 2 -#define PY_ITERSEARCH_CONTAINS 3 - -/* Iterate over seq. - - Result depends on the operation: - - PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if - error. - PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of - obj in seq; set ValueError and return -1 if none found; - also return -1 on error. - PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on - error. */ -PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, - PyObject *obj, int operation); - /* === Mapping protocol ================================================= */ PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); diff --git a/Include/internal/pycore_abstract.h b/Include/internal/pycore_abstract.h index b1afb2dc7be65e..9ba27487f5bbf1 100644 --- a/Include/internal/pycore_abstract.h +++ b/Include/internal/pycore_abstract.h @@ -19,6 +19,28 @@ _PyIndex_Check(PyObject *obj) PyObject *_PyNumber_PowerNoMod(PyObject *lhs, PyObject *rhs); PyObject *_PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs); +extern int _PyObject_HasLen(PyObject *o); + +/* === Sequence protocol ================================================ */ + +#define PY_ITERSEARCH_COUNT 1 +#define PY_ITERSEARCH_INDEX 2 +#define PY_ITERSEARCH_CONTAINS 3 + +/* Iterate over seq. + + Result depends on the operation: + + PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if + error. + PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of + obj in seq; set ValueError and return -1 if none found; + also return -1 on error. + PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on + error. */ +extern Py_ssize_t _PySequence_IterSearch(PyObject *seq, + PyObject *obj, int operation); + #ifdef __cplusplus } #endif diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 7cb17a6ca4ab56..cf7cb8af52a274 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -1,6 +1,7 @@ /* Iterator objects */ #include "Python.h" +#include "pycore_abstract.h" // _PyObject_HasLen() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_object.h" // _PyObject_GC_TRACK() diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9aba53df157910..e3769cee2c3972 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1,11 +1,11 @@ /* Type object implementation */ #include "Python.h" -#include "pycore_call.h" +#include "pycore_abstract.h" // _PySequence_IterSearch() +#include "pycore_call.h" // _PyObject_VectorcallTstate() #include "pycore_code.h" // CO_FAST_FREE #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_frame.h" // _PyInterpreterFrame -#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() #include "pycore_moduleobject.h" // _PyModule_GetDef() From e8e59ee474869e7c02e7cae3815c9c2183671b21 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 15:38:41 +0200 Subject: [PATCH 145/446] gh-106084: Remove _PyObject_RealIsInstance() function (#106106) Remove the following functions from the public C API: * _PyObject_RealIsInstance() * _PyObject_RealIsSubclass() * _Py_add_one_to_index_F() * _Py_add_one_to_index_C() Move _PyObject_RealIsInstance() and _PyObject_RealIsSubclass() to the internal C API (pycore_abstract.h) and no longer export their symbols (in libpython). Make _Py_add_one_to_index_F() and _Py_add_one_to_index_C() functions static: no longer export them. --- Include/cpython/abstract.h | 16 ++++------------ Include/internal/pycore_abstract.h | 7 +++++++ Objects/abstract.c | 4 ++-- Objects/descrobject.c | 1 + Objects/exceptions.c | 1 + 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index cba0f4c3130921..5eb22ff61ecddc 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -147,18 +147,10 @@ PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); /* === Mapping protocol ================================================= */ -PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); - -PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); - -/* For internal use by buffer API functions */ -PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); -PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index, - const Py_ssize_t *shape); - -/* Convert Python int to Py_ssize_t. Do nothing if the argument is None. */ +// Convert Python int to Py_ssize_t. Do nothing if the argument is None. +// Cannot be moved to the internal C API: used by Argument Clinic. PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *); -/* Same as PyNumber_Index but can return an instance of a subclass of int. */ +// Same as PyNumber_Index but can return an instance of a subclass of int. +// Cannot be moved to the internal C API: used by Argument Clinic. PyAPI_FUNC(PyObject *) _PyNumber_Index(PyObject *o); diff --git a/Include/internal/pycore_abstract.h b/Include/internal/pycore_abstract.h index 9ba27487f5bbf1..2733d8102e5ef4 100644 --- a/Include/internal/pycore_abstract.h +++ b/Include/internal/pycore_abstract.h @@ -41,6 +41,13 @@ extern int _PyObject_HasLen(PyObject *o); extern Py_ssize_t _PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation); +/* === Mapping protocol ================================================= */ + +extern int _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); + +extern int _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); + + #ifdef __cplusplus } #endif diff --git a/Objects/abstract.c b/Objects/abstract.c index fecdb4e07239a2..80a40944d6d219 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -517,7 +517,7 @@ PyBuffer_GetPointer(const Py_buffer *view, const Py_ssize_t *indices) } -void +static void _Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape) { int k; @@ -533,7 +533,7 @@ _Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape) } } -void +static void _Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape) { int k; diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 98d8698fa70fbc..89bac99bb9d638 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1,6 +1,7 @@ /* Descriptors -- a new, flexible way to describe attributes */ #include "Python.h" +#include "pycore_abstract.h" // _PyObject_RealIsSubclass() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pystate.h" // _PyThreadState_GET() diff --git a/Objects/exceptions.c b/Objects/exceptions.c index f27e6f6c1431a0..015dd27ec33308 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -7,6 +7,7 @@ #define PY_SSIZE_T_CLEAN #include #include +#include "pycore_abstract.h" // _PyObject_RealIsSubclass() #include "pycore_ceval.h" // _Py_EnterRecursiveCall #include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException #include "pycore_exceptions.h" // struct _Py_exc_state From 1a2bc94fc2bbdf5f810b441ebbbd8fec95a3207c Mon Sep 17 00:00:00 2001 From: Bruce Eckel Date: Mon, 26 Jun 2023 08:30:20 -0700 Subject: [PATCH 146/446] Update test.support.interpreters to include missing RunFailedError import (#103841) Co-authored-by: Alex Waygood --- Lib/test/support/interpreters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/interpreters.py b/Lib/test/support/interpreters.py index eeff3abe0324e5..5c484d1170d1d9 100644 --- a/Lib/test/support/interpreters.py +++ b/Lib/test/support/interpreters.py @@ -5,7 +5,7 @@ import _xxinterpchannels as _channels # aliases: -from _xxsubinterpreters import is_shareable +from _xxsubinterpreters import is_shareable, RunFailedError from _xxinterpchannels import ( ChannelError, ChannelNotFoundError, ChannelEmptyError, ) From 5d4dbf0e309255e5bce9e31d805a8f950ebf9161 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 26 Jun 2023 17:14:20 +0100 Subject: [PATCH 147/446] gh-106111: Remove zipapp documentation on creating a Windows executable (#106112) Remove zipapp documentation on creating a Windows executable --- Doc/library/zipapp.rst | 115 ++++------------------------------------- 1 file changed, 9 insertions(+), 106 deletions(-) diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index 981020b13cd988..8cee85b32d2a83 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -303,115 +303,18 @@ the Python interpreter registers the ``.pyz`` and ``.pyzw`` file extensions when installed. -Making a Windows executable -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On Windows, registration of the ``.pyz`` extension is optional, and -furthermore, there are certain places that don't recognise registered -extensions "transparently" (the simplest example is that -``subprocess.run(['myapp'])`` won't find your application - you need to -explicitly specify the extension). - -On Windows, therefore, it is often preferable to create an executable from the -zipapp. This is relatively easy, although it does require a C compiler. The -basic approach relies on the fact that zipfiles can have arbitrary data -prepended, and Windows exe files can have arbitrary data appended. So by -creating a suitable launcher and tacking the ``.pyz`` file onto the end of it, -you end up with a single-file executable that runs your application. - -A suitable launcher can be as simple as the following:: - - #define Py_LIMITED_API 1 - #include "Python.h" - - #define WIN32_LEAN_AND_MEAN - #include - - #ifdef WINDOWS - int WINAPI wWinMain( - HINSTANCE hInstance, /* handle to current instance */ - HINSTANCE hPrevInstance, /* handle to previous instance */ - LPWSTR lpCmdLine, /* pointer to command line */ - int nCmdShow /* show state of window */ - ) - #else - int wmain() - #endif - { - wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*)); - myargv[0] = __wargv[0]; - memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *)); - return Py_Main(__argc+1, myargv); - } - -If you define the ``WINDOWS`` preprocessor symbol, this will generate a -GUI executable, and without it, a console executable. - -To compile the executable, you can either just use the standard MSVC -command line tools, or you can take advantage of the fact that distutils -knows how to compile Python source:: - - >>> from distutils.ccompiler import new_compiler - >>> import distutils.sysconfig - >>> import sys - >>> import os - >>> from pathlib import Path - - >>> def compile(src): - >>> src = Path(src) - >>> cc = new_compiler() - >>> exe = src.stem - >>> cc.add_include_dir(distutils.sysconfig.get_python_inc()) - >>> cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs')) - >>> # First the CLI executable - >>> objs = cc.compile([str(src)]) - >>> cc.link_executable(objs, exe) - >>> # Now the GUI executable - >>> cc.define_macro('WINDOWS') - >>> objs = cc.compile([str(src)]) - >>> cc.link_executable(objs, exe + 'w') - - >>> if __name__ == "__main__": - >>> compile("zastub.c") - -The resulting launcher uses the "Limited ABI", so it will run unchanged with -any version of Python 3.x. All it needs is for Python (``python3.dll``) to be -on the user's ``PATH``. - -For a fully standalone distribution, you can distribute the launcher with your -application appended, bundled with the Python "embedded" distribution. This -will run on any PC with the appropriate architecture (32 bit or 64 bit). - - Caveats ~~~~~~~ -There are some limitations to the process of bundling your application into -a single file. In most, if not all, cases they can be addressed without -needing major changes to your application. - -1. If your application depends on a package that includes a C extension, that - package cannot be run from a zip file (this is an OS limitation, as executable - code must be present in the filesystem for the OS loader to load it). In this - case, you can exclude that dependency from the zipfile, and either require - your users to have it installed, or ship it alongside your zipfile and add code - to your ``__main__.py`` to include the directory containing the unzipped - module in ``sys.path``. In this case, you will need to make sure to ship - appropriate binaries for your target architecture(s) (and potentially pick the - correct version to add to ``sys.path`` at runtime, based on the user's machine). - -2. If you are shipping a Windows executable as described above, you either need to - ensure that your users have ``python3.dll`` on their PATH (which is not the - default behaviour of the installer) or you should bundle your application with - the embedded distribution. - -3. The suggested launcher above uses the Python embedding API. This means that in - your application, ``sys.executable`` will be your application, and *not* a - conventional Python interpreter. Your code and its dependencies need to be - prepared for this possibility. For example, if your application uses the - :mod:`multiprocessing` module, it will need to call - :func:`multiprocessing.set_executable` to let the module know where to find the - standard Python interpreter. +If your application depends on a package that includes a C extension, that +package cannot be run from a zip file (this is an OS limitation, as executable +code must be present in the filesystem for the OS loader to load it). In this +case, you can exclude that dependency from the zipfile, and either require +your users to have it installed, or ship it alongside your zipfile and add code +to your ``__main__.py`` to include the directory containing the unzipped +module in ``sys.path``. In this case, you will need to make sure to ship +appropriate binaries for your target architecture(s) (and potentially pick the +correct version to add to ``sys.path`` at runtime, based on the user's machine). The Python Zip Application Archive Format From 219effa876785408a87bd6acb37c07ee0d25f3f9 Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Mon, 26 Jun 2023 17:58:17 +0100 Subject: [PATCH 148/446] GH-105793: Add follow_symlinks argument to `pathlib.Path.is_dir()` and `is_file()` (GH-105794) Brings `pathlib.Path.is_dir()` and `in line with `os.DirEntry.is_dir()`, which will be important for implementing generic path walking and globbing. Likewise `is_file()`. --- Doc/library/pathlib.rst | 24 +++++++++---- Doc/whatsnew/3.13.rst | 7 ++-- Lib/pathlib.py | 8 ++--- Lib/test/test_pathlib.py | 36 ++++++++++++++++--- ...-06-14-18-41-18.gh-issue-105793.YSoykM.rst | 2 ++ 5 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-14-18-41-18.gh-issue-105793.YSoykM.rst diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 9bbfe384ce54c4..338575404ff0ad 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -978,23 +978,35 @@ call fails (for example because the path doesn't exist). available. In previous versions, :exc:`NotImplementedError` was raised. -.. method:: Path.is_dir() +.. method:: Path.is_dir(*, follow_symlinks=True) - Return ``True`` if the path points to a directory (or a symbolic link - pointing to a directory), ``False`` if it points to another kind of file. + Return ``True`` if the path points to a directory, ``False`` if it points + to another kind of file. ``False`` is also returned if the path doesn't exist or is a broken symlink; other errors (such as permission errors) are propagated. + This method normally follows symlinks; to exclude symlinks to directories, + add the argument ``follow_symlinks=False``. -.. method:: Path.is_file() + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. + + +.. method:: Path.is_file(*, follow_symlinks=True) - Return ``True`` if the path points to a regular file (or a symbolic link - pointing to a regular file), ``False`` if it points to another kind of file. + Return ``True`` if the path points to a regular file, ``False`` if it + points to another kind of file. ``False`` is also returned if the path doesn't exist or is a broken symlink; other errors (such as permission errors) are propagated. + This method normally follows symlinks; to exclude symlinks, add the + argument ``follow_symlinks=False``. + + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. + .. method:: Path.is_junction() diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index b6d13a8aac0f0e..f3460beeb16be6 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -113,9 +113,10 @@ pathlib * Add support for recursive wildcards in :meth:`pathlib.PurePath.match`. (Contributed by Barney Gale in :gh:`73435`.) -* Add *follow_symlinks* keyword-only argument to :meth:`pathlib.Path.glob` and - :meth:`~pathlib.Path.rglob`. - (Contributed by Barney Gale in :gh:`77609`.) +* Add *follow_symlinks* keyword-only argument to :meth:`pathlib.Path.glob`, + :meth:`~pathlib.Path.rglob`, :meth:`~pathlib.Path.is_file`, and + :meth:`~pathlib.Path.is_dir`. + (Contributed by Barney Gale in :gh:`77609` and :gh:`105793`.) traceback --------- diff --git a/Lib/pathlib.py b/Lib/pathlib.py index a36ffdd73d8af1..e15718dc98d677 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -817,12 +817,12 @@ def exists(self, *, follow_symlinks=True): return False return True - def is_dir(self): + def is_dir(self, *, follow_symlinks=True): """ Whether this path is a directory. """ try: - return S_ISDIR(self.stat().st_mode) + return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode) except OSError as e: if not _ignore_error(e): raise @@ -833,13 +833,13 @@ def is_dir(self): # Non-encodable path return False - def is_file(self): + def is_file(self, *, follow_symlinks=True): """ Whether this path is a regular file (also True for symlinks pointing to regular files). """ try: - return S_ISREG(self.stat().st_mode) + return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode) except OSError as e: if not _ignore_error(e): raise diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f9356909cb0982..eeb522bb160523 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2191,9 +2191,22 @@ def test_is_dir(self): if os_helper.can_symlink(): self.assertFalse((P / 'linkA').is_dir()) self.assertTrue((P / 'linkB').is_dir()) - self.assertFalse((P/ 'brokenLink').is_dir(), False) - self.assertIs((P / 'dirA\udfff').is_dir(), False) - self.assertIs((P / 'dirA\x00').is_dir(), False) + self.assertFalse((P/ 'brokenLink').is_dir()) + self.assertFalse((P / 'dirA\udfff').is_dir()) + self.assertFalse((P / 'dirA\x00').is_dir()) + + def test_is_dir_no_follow_symlinks(self): + P = self.cls(BASE) + self.assertTrue((P / 'dirA').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'fileA').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'non-existing').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'fileA' / 'bah').is_dir(follow_symlinks=False)) + if os_helper.can_symlink(): + self.assertFalse((P / 'linkA').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'linkB').is_dir(follow_symlinks=False)) + self.assertFalse((P/ 'brokenLink').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'dirA\udfff').is_dir(follow_symlinks=False)) + self.assertFalse((P / 'dirA\x00').is_dir(follow_symlinks=False)) def test_is_file(self): P = self.cls(BASE) @@ -2205,8 +2218,21 @@ def test_is_file(self): self.assertTrue((P / 'linkA').is_file()) self.assertFalse((P / 'linkB').is_file()) self.assertFalse((P/ 'brokenLink').is_file()) - self.assertIs((P / 'fileA\udfff').is_file(), False) - self.assertIs((P / 'fileA\x00').is_file(), False) + self.assertFalse((P / 'fileA\udfff').is_file()) + self.assertFalse((P / 'fileA\x00').is_file()) + + def test_is_file_no_follow_symlinks(self): + P = self.cls(BASE) + self.assertTrue((P / 'fileA').is_file(follow_symlinks=False)) + self.assertFalse((P / 'dirA').is_file(follow_symlinks=False)) + self.assertFalse((P / 'non-existing').is_file(follow_symlinks=False)) + self.assertFalse((P / 'fileA' / 'bah').is_file(follow_symlinks=False)) + if os_helper.can_symlink(): + self.assertFalse((P / 'linkA').is_file(follow_symlinks=False)) + self.assertFalse((P / 'linkB').is_file(follow_symlinks=False)) + self.assertFalse((P/ 'brokenLink').is_file(follow_symlinks=False)) + self.assertFalse((P / 'fileA\udfff').is_file(follow_symlinks=False)) + self.assertFalse((P / 'fileA\x00').is_file(follow_symlinks=False)) def test_is_mount(self): P = self.cls(BASE) diff --git a/Misc/NEWS.d/next/Library/2023-06-14-18-41-18.gh-issue-105793.YSoykM.rst b/Misc/NEWS.d/next/Library/2023-06-14-18-41-18.gh-issue-105793.YSoykM.rst new file mode 100644 index 00000000000000..0e4090ea7eabb9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-14-18-41-18.gh-issue-105793.YSoykM.rst @@ -0,0 +1,2 @@ +Add *follow_symlinks* keyword-only argument to :meth:`pathlib.Path.is_dir` and +:meth:`~pathlib.Path.is_file`, defaulting to ``True``. From 512f299e557f4ab60768d36cee9968bd92116367 Mon Sep 17 00:00:00 2001 From: Roderich Schupp Date: Mon, 26 Jun 2023 20:00:21 +0200 Subject: [PATCH 149/446] gh-106107: document correct error that's raised when a mutable default value for a field is detected (gh-106109) --- Doc/library/dataclasses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index a5b20149921042..535a60ccca8d07 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -738,7 +738,7 @@ for ``x`` when creating a class instance will share the same copy of ``x``. Because dataclasses just use normal Python class creation they also share this behavior. There is no general way for Data Classes to detect this condition. Instead, the -:func:`dataclass` decorator will raise a :exc:`TypeError` if it +:func:`dataclass` decorator will raise a :exc:`ValueError` if it detects an unhashable default parameter. The assumption is that if a value is unhashable, it is mutable. This is a partial solution, but it does protect against many common errors. From d3af83b9342457d8b24476baeb799f7506ff04f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Mon, 26 Jun 2023 18:35:53 +0000 Subject: [PATCH 150/446] Revert "GH-96145: Add AttrDict to JSON module for use with object_hook (#96146)" (#105948) This reverts commit 1f0eafa844bf5a380603d55e8d4b42d8c2a3439d. --- Doc/library/json.rst | 43 ------ Doc/whatsnew/3.12.rst | 8 - Lib/json/__init__.py | 52 +------ Lib/test/test_json/__init__.py | 1 - Lib/test/test_json/test_attrdict.py | 145 ------------------ ...3-06-20-23-18-45.gh-issue-96145.o5dTRM.rst | 1 + 6 files changed, 2 insertions(+), 248 deletions(-) delete mode 100644 Lib/test/test_json/test_attrdict.py create mode 100644 Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst diff --git a/Doc/library/json.rst b/Doc/library/json.rst index ef58dd09423640..5383614575c213 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -9,11 +9,6 @@ **Source code:** :source:`Lib/json/__init__.py` -.. testsetup:: * - - import json - from json import AttrDict - -------------- `JSON (JavaScript Object Notation) `_, specified by @@ -548,44 +543,6 @@ Exceptions .. versionadded:: 3.5 -.. class:: AttrDict(**kwargs) - AttrDict(mapping, **kwargs) - AttrDict(iterable, **kwargs) - - Subclass of :class:`dict` that also supports attribute style dotted access. - - This class is intended for use with the :attr:`object_hook` in - :func:`json.load` and :func:`json.loads`: - - .. doctest:: - - >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' - >>> orbital_period = json.loads(json_string, object_hook=AttrDict) - >>> orbital_period['earth'] # Dict style lookup - 365 - >>> orbital_period.earth # Attribute style lookup - 365 - >>> orbital_period.keys() # All dict methods are present - dict_keys(['mercury', 'venus', 'earth', 'mars']) - - Attribute style access only works for keys that are valid attribute - names. In contrast, dictionary style access works for all keys. For - example, ``d.two words`` contains a space and is not syntactically - valid Python, so ``d["two words"]`` should be used instead. - - If a key has the same name as a dictionary method, then a dictionary - lookup finds the key and an attribute lookup finds the method: - - .. doctest:: - - >>> d = AttrDict(items=50) - >>> d['items'] # Lookup the key - 50 - >>> d.items() # Call the method - dict_items([('items', 50)]) - - .. versionadded:: 3.12 - Standard Compliance and Interoperability ---------------------------------------- diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d8a236080c0056..b6382e7e984490 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -593,14 +593,6 @@ itertools tuples where the last batch may be shorter than the rest. (Contributed by Raymond Hettinger in :gh:`98363`.) -json ----- - -* Added :class:`json.AttrDict` for use with ``object_hook`` in :func:`json.load` - or :func:`json.loads`. This is a subclass of :class:`dict` that also supports - attribute style dotted access. - (Contributed by Raymond Hettinger in :gh:`96145`.) - math ---- diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 256e76a0a67f8f..ed2c74771ea87d 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -97,7 +97,7 @@ """ __version__ = '2.0.9' __all__ = [ - 'dump', 'dumps', 'load', 'loads', 'AttrDict', + 'dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', ] @@ -357,53 +357,3 @@ def loads(s, *, cls=None, object_hook=None, parse_float=None, if parse_constant is not None: kw['parse_constant'] = parse_constant return cls(**kw).decode(s) - -class AttrDict(dict): - """Dict like object that supports attribute style dotted access. - - This class is intended for use with the *object_hook* in json.loads(): - - >>> from json import loads, AttrDict - >>> json_string = '{"mercury": 88, "venus": 225, "earth": 365, "mars": 687}' - >>> orbital_period = loads(json_string, object_hook=AttrDict) - >>> orbital_period['earth'] # Dict style lookup - 365 - >>> orbital_period.earth # Attribute style lookup - 365 - >>> orbital_period.keys() # All dict methods are present - dict_keys(['mercury', 'venus', 'earth', 'mars']) - - Attribute style access only works for keys that are valid attribute names. - In contrast, dictionary style access works for all keys. - For example, ``d.two words`` contains a space and is not syntactically - valid Python, so ``d["two words"]`` should be used instead. - - If a key has the same name as dictionary method, then a dictionary - lookup finds the key and an attribute lookup finds the method: - - >>> d = AttrDict(items=50) - >>> d['items'] # Lookup the key - 50 - >>> d.items() # Call the method - dict_items([('items', 50)]) - - """ - __slots__ = () - - def __getattr__(self, attr): - try: - return self[attr] - except KeyError: - raise AttributeError(attr) from None - - def __setattr__(self, attr, value): - self[attr] = value - - def __delattr__(self, attr): - try: - del self[attr] - except KeyError: - raise AttributeError(attr) from None - - def __dir__(self): - return list(self) + dir(type(self)) diff --git a/Lib/test/test_json/__init__.py b/Lib/test/test_json/__init__.py index 37b2e0d5e26d16..74b64ed86a3183 100644 --- a/Lib/test/test_json/__init__.py +++ b/Lib/test/test_json/__init__.py @@ -18,7 +18,6 @@ class PyTest(unittest.TestCase): json = pyjson loads = staticmethod(pyjson.loads) dumps = staticmethod(pyjson.dumps) - AttrDict = pyjson.AttrDict JSONDecodeError = staticmethod(pyjson.JSONDecodeError) @unittest.skipUnless(cjson, 'requires _json') diff --git a/Lib/test/test_json/test_attrdict.py b/Lib/test/test_json/test_attrdict.py deleted file mode 100644 index 143ea462d310aa..00000000000000 --- a/Lib/test/test_json/test_attrdict.py +++ /dev/null @@ -1,145 +0,0 @@ -from test.test_json import PyTest -import pickle -import sys -import unittest - -kepler_dict = { - "orbital_period": { - "mercury": 88, - "venus": 225, - "earth": 365, - "mars": 687, - "jupiter": 4331, - "saturn": 10_756, - "uranus": 30_687, - "neptune": 60_190, - }, - "dist_from_sun": { - "mercury": 58, - "venus": 108, - "earth": 150, - "mars": 228, - "jupiter": 778, - "saturn": 1_400, - "uranus": 2_900, - "neptune": 4_500, - } -} - -class TestAttrDict(PyTest): - - def test_dict_subclass(self): - self.assertTrue(issubclass(self.AttrDict, dict)) - - def test_slots(self): - d = self.AttrDict(x=1, y=2) - with self.assertRaises(TypeError): - vars(d) - - def test_constructor_signatures(self): - AttrDict = self.AttrDict - target = dict(x=1, y=2) - self.assertEqual(AttrDict(x=1, y=2), target) # kwargs - self.assertEqual(AttrDict(dict(x=1, y=2)), target) # mapping - self.assertEqual(AttrDict(dict(x=1, y=0), y=2), target) # mapping, kwargs - self.assertEqual(AttrDict([('x', 1), ('y', 2)]), target) # iterable - self.assertEqual(AttrDict([('x', 1), ('y', 0)], y=2), target) # iterable, kwargs - - def test_getattr(self): - d = self.AttrDict(x=1, y=2) - self.assertEqual(d.x, 1) - with self.assertRaises(AttributeError): - d.z - - def test_setattr(self): - d = self.AttrDict(x=1, y=2) - d.x = 3 - d.z = 5 - self.assertEqual(d, dict(x=3, y=2, z=5)) - - def test_delattr(self): - d = self.AttrDict(x=1, y=2) - del d.x - self.assertEqual(d, dict(y=2)) - with self.assertRaises(AttributeError): - del d.z - - def test_dir(self): - d = self.AttrDict(x=1, y=2) - self.assertTrue(set(dir(d)), set(dir(dict)).union({'x', 'y'})) - - def test_repr(self): - # This repr is doesn't round-trip. It matches a regular dict. - # That seems to be the norm for AttrDict recipes being used - # in the wild. Also it supports the design concept that an - # AttrDict is just like a regular dict but has optional - # attribute style lookup. - self.assertEqual(repr(self.AttrDict(x=1, y=2)), - repr(dict(x=1, y=2))) - - def test_overlapping_keys_and_methods(self): - d = self.AttrDict(items=50) - self.assertEqual(d['items'], 50) - self.assertEqual(d.items(), dict(d).items()) - - def test_invalid_attribute_names(self): - d = self.AttrDict({ - 'control': 'normal case', - 'class': 'keyword', - 'two words': 'contains space', - 'hypen-ate': 'contains a hyphen' - }) - self.assertEqual(d.control, dict(d)['control']) - self.assertEqual(d['class'], dict(d)['class']) - self.assertEqual(d['two words'], dict(d)['two words']) - self.assertEqual(d['hypen-ate'], dict(d)['hypen-ate']) - - def test_object_hook_use_case(self): - AttrDict = self.AttrDict - json_string = self.dumps(kepler_dict) - kepler_ad = self.loads(json_string, object_hook=AttrDict) - - self.assertEqual(kepler_ad, kepler_dict) # Match regular dict - self.assertIsInstance(kepler_ad, AttrDict) # Verify conversion - self.assertIsInstance(kepler_ad.orbital_period, AttrDict) # Nested - - # Exercise dotted lookups - self.assertEqual(kepler_ad.orbital_period, kepler_dict['orbital_period']) - self.assertEqual(kepler_ad.orbital_period.earth, - kepler_dict['orbital_period']['earth']) - self.assertEqual(kepler_ad['orbital_period'].earth, - kepler_dict['orbital_period']['earth']) - - # Dict style error handling and Attribute style error handling - with self.assertRaises(KeyError): - kepler_ad.orbital_period['pluto'] - with self.assertRaises(AttributeError): - kepler_ad.orbital_period.Pluto - - # Order preservation - self.assertEqual(list(kepler_ad.items()), list(kepler_dict.items())) - self.assertEqual(list(kepler_ad.orbital_period.items()), - list(kepler_dict['orbital_period'].items())) - - # Round trip - self.assertEqual(self.dumps(kepler_ad), json_string) - - def test_pickle(self): - AttrDict = self.AttrDict - json_string = self.dumps(kepler_dict) - kepler_ad = self.loads(json_string, object_hook=AttrDict) - - # Pickling requires the cached module to be the real module - cached_module = sys.modules.get('json') - sys.modules['json'] = self.json - try: - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): - kepler_ad2 = pickle.loads(pickle.dumps(kepler_ad, protocol)) - self.assertEqual(kepler_ad2, kepler_ad) - self.assertEqual(type(kepler_ad2), AttrDict) - finally: - sys.modules['json'] = cached_module - - -if __name__ == "__main__": - unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst b/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst new file mode 100644 index 00000000000000..f4fb0e46ce5e57 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-20-23-18-45.gh-issue-96145.o5dTRM.rst @@ -0,0 +1 @@ +Reverted addition of ``json.AttrDict``. From 51fc72511733353de15bc633a3d7b6da366842e4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 26 Jun 2023 19:02:57 -0700 Subject: [PATCH 151/446] gh-104584: Baby steps towards generating and executing traces (#105924) Added a new, experimental, tracing optimizer and interpreter (a.k.a. "tier 2"). This currently pessimizes, so don't use yet -- this is infrastructure so we can experiment with optimizing passes. To enable it, pass ``-Xuops`` or set ``PYTHONUOPS=1``. To get debug output, set ``PYTHONUOPSDEBUG=N`` where ``N`` is a debug level (0-4, where 0 is no debug output and 4 is excessively verbose). All of this code is likely to change dramatically before the 3.13 feature freeze. But this is a first step. --- .gitattributes | 1 + Include/cpython/optimizer.h | 1 + Include/internal/pycore_uops.h | 31 + Include/pystats.h | 3 + Makefile.pre.in | 21 +- ...-06-27-00-58-26.gh-issue-104584.Wu-uXy.rst | 1 + Modules/_testinternalcapi.c | 7 + Python/bytecodes.c | 4 +- Python/ceval.c | 137 +- Python/ceval_macros.h | 10 +- Python/executor_cases.c.h | 1606 +++++++++++++++++ Python/generated_cases.c.h | 518 +++--- Python/opcode_metadata.h | 106 ++ Python/optimizer.c | 199 ++ Python/pylifecycle.c | 13 + Python/specialize.c | 4 + Tools/c-analyzer/cpython/_parser.py | 1 + Tools/c-analyzer/cpython/ignored.tsv | 2 + Tools/cases_generator/README.md | 2 +- Tools/cases_generator/generate_cases.py | 187 +- Tools/cases_generator/test_generator.py | 10 +- 21 files changed, 2559 insertions(+), 305 deletions(-) create mode 100644 Include/internal/pycore_uops.h create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-27-00-58-26.gh-issue-104584.Wu-uXy.rst create mode 100644 Python/executor_cases.c.h diff --git a/.gitattributes b/.gitattributes index bab1ef0d010460..a2ff14c66323e2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -86,6 +86,7 @@ Parser/token.c generated Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/generated_cases.c.h generated +Python/executor_cases.c.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h index b2d173fb913eeb..2664f5bc4b1742 100644 --- a/Include/cpython/optimizer.h +++ b/Include/cpython/optimizer.h @@ -45,6 +45,7 @@ extern _PyOptimizerObject _PyOptimizer_Default; /* For testing */ PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void); +PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewUOpOptimizer(void); #define OPTIMIZER_BITS_IN_COUNTER 4 diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h new file mode 100644 index 00000000000000..0e88d7e7f4a3bd --- /dev/null +++ b/Include/internal/pycore_uops.h @@ -0,0 +1,31 @@ +#ifndef Py_INTERNAL_UOPS_H +#define Py_INTERNAL_UOPS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#define _Py_UOP_MAX_TRACE_LENGTH 16 + +typedef struct { + int opcode; + uint64_t operand; // Sometimes oparg, sometimes a cache entry +} _PyUOpInstruction; + +typedef struct { + _PyExecutorObject base; + _PyUOpInstruction trace[_Py_UOP_MAX_TRACE_LENGTH]; // TODO: variable length +} _PyUOpExecutorObject; + +_PyInterpreterFrame *_PyUopExecute( + _PyExecutorObject *executor, + _PyInterpreterFrame *frame, + PyObject **stack_pointer); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_UOPS_H */ diff --git a/Include/pystats.h b/Include/pystats.h index 034bf05bfe290f..54c9b8d8b3538f 100644 --- a/Include/pystats.h +++ b/Include/pystats.h @@ -71,6 +71,9 @@ typedef struct _object_stats { uint64_t type_cache_dunder_misses; uint64_t type_cache_collisions; uint64_t optimization_attempts; + uint64_t optimization_traces_created; + uint64_t optimization_traces_executed; + uint64_t optimization_uops_executed; } ObjectStats; typedef struct _stats { diff --git a/Makefile.pre.in b/Makefile.pre.in index e9a8d8ffb71fd2..98b58cf1299f16 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1542,19 +1542,9 @@ regen-opcode-targets: .PHONY: regen-cases regen-cases: - # Regenerate Python/generated_cases.c.h - # and Python/opcode_metadata.h - # from Python/bytecodes.c - # using Tools/cases_generator/generate_cases.py + # Regenerate various files from Python/bytecodes.c PYTHONPATH=$(srcdir)/Tools/cases_generator \ - $(PYTHON_FOR_REGEN) \ - $(srcdir)/Tools/cases_generator/generate_cases.py \ - --emit-line-directives \ - -o $(srcdir)/Python/generated_cases.c.h.new \ - -m $(srcdir)/Python/opcode_metadata.h.new \ - $(srcdir)/Python/bytecodes.c - $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new - $(UPDATE_FILE) $(srcdir)/Python/opcode_metadata.h $(srcdir)/Python/opcode_metadata.h.new + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/generate_cases.py -l Python/compile.o: $(srcdir)/Python/opcode_metadata.h @@ -1565,6 +1555,13 @@ Python/ceval.o: \ $(srcdir)/Python/opcode_metadata.h \ $(srcdir)/Python/opcode_targets.h +Python/flowgraph.o: \ + $(srcdir)/Python/opcode_metadata.h + +Python/optimizer.o: \ + $(srcdir)/Python/executor_cases.c.h \ + $(srcdir)/Python/opcode_metadata.h + Python/frozen.o: $(FROZEN_FILES_OUT) # Generate DTrace probe macros, then rename them (PYTHON_ -> PyDTrace_) to diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-27-00-58-26.gh-issue-104584.Wu-uXy.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-27-00-58-26.gh-issue-104584.Wu-uXy.rst new file mode 100644 index 00000000000000..a36490104ba3aa --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-27-00-58-26.gh-issue-104584.Wu-uXy.rst @@ -0,0 +1 @@ +Added a new, experimental, tracing optimizer and interpreter (a.k.a. "tier 2"). This currently pessimizes, so don't use yet -- this is infrastructure so we can experiment with optimizing passes. To enable it, pass ``-Xuops`` or set ``PYTHONUOPS=1``. To get debug output, set ``PYTHONUOPSDEBUG=N`` where ``N`` is a debug level (0-4, where 0 is no debug output and 4 is excessively verbose). diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 0a3b0dd539e862..3c0c2adaf6f843 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -830,6 +830,12 @@ get_counter_optimizer(PyObject *self, PyObject *arg) return PyUnstable_Optimizer_NewCounter(); } +static PyObject * +get_uop_optimizer(PyObject *self, PyObject *arg) +{ + return PyUnstable_Optimizer_NewUOpOptimizer(); +} + static PyObject * set_optimizer(PyObject *self, PyObject *opt) { @@ -994,6 +1000,7 @@ static PyMethodDef module_functions[] = { {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, {"get_counter_optimizer", get_counter_optimizer, METH_NOARGS, NULL}, + {"get_uop_optimizer", get_uop_optimizer, METH_NOARGS, NULL}, {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), METH_VARARGS | METH_KEYWORDS}, // {"pending_fd_identify", pending_fd_identify, METH_VARARGS, NULL}, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3ef8ed0ccaafdc..02857104f5a4d5 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -52,8 +52,6 @@ #define family(name, ...) static int family_##name #define pseudo(name) static int pseudo_##name -typedef PyObject *(*convertion_func_ptr)(PyObject *); - // Dummy variables for stack effects. static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2; @@ -2182,7 +2180,7 @@ dummy_func( frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; - goto error; + goto resume_with_error; } goto resume_frame; } diff --git a/Python/ceval.c b/Python/ceval.c index 53107018978c0b..3e0dcf8c8629b9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -22,6 +22,7 @@ #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_typeobject.h" // _PySuper_Lookup() +#include "pycore_uops.h" // _PyUOpExecutorObject #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_dict.h" @@ -223,14 +224,6 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, static void _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); -typedef PyObject *(*convertion_func_ptr)(PyObject *); - -static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = { - [FVC_STR] = PyObject_Str, - [FVC_REPR] = PyObject_Repr, - [FVC_ASCII] = PyObject_ASCII -}; - #define UNBOUNDLOCAL_ERROR_MSG \ "cannot access local variable '%s' where it is not associated with a value" #define UNBOUNDFREE_ERROR_MSG \ @@ -2771,3 +2764,131 @@ void Py_LeaveRecursiveCall(void) { _Py_LeaveRecursiveCall(); } + +///////////////////// Experimental UOp Interpreter ///////////////////// + +// UPDATE_MISS_STATS (called by DEOPT_IF) uses next_instr +// TODO: Make it do something useful +#undef UPDATE_MISS_STATS +#define UPDATE_MISS_STATS(INSTNAME) ((void)0) + +_PyInterpreterFrame * +_PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer) +{ +#ifdef LLTRACE + char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); + int lltrace = 0; + if (uop_debug != NULL && *uop_debug >= '0') { + lltrace = *uop_debug - '0'; // TODO: Parse an int and all that + } + if (lltrace >= 2) { + PyCodeObject *code = _PyFrame_GetCode(frame); + _Py_CODEUNIT *instr = frame->prev_instr + 1; + fprintf(stderr, + "Entering _PyUopExecute for %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + } +#endif + + PyThreadState *tstate = _PyThreadState_GET(); + _PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor; + + // Equivalent to CHECK_EVAL_BREAKER() + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { + if (_Py_HandlePending(tstate) != 0) { + goto error; + } + } + + OBJECT_STAT_INC(optimization_traces_executed); + _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive - 1; + int pc = 0; + int opcode; + uint64_t operand; + int oparg; + for (;;) { + opcode = self->trace[pc].opcode; + operand = self->trace[pc].operand; + oparg = (int)operand; +#ifdef LLTRACE + if (lltrace >= 3) { + const char *opname = opcode < 256 ? _PyOpcode_OpName[opcode] : ""; + int stack_level = (int)(stack_pointer - _PyFrame_Stackbase(frame)); + fprintf(stderr, " uop %s %d, operand %" PRIu64 ", stack_level %d\n", + opname, opcode, operand, stack_level); + } +#endif + pc++; + OBJECT_STAT_INC(optimization_uops_executed); + switch (opcode) { + +#undef ENABLE_SPECIALIZATION +#define ENABLE_SPECIALIZATION 0 +#include "executor_cases.c.h" + + case SET_IP: + { + frame->prev_instr = ip_offset + oparg; + break; + } + + case EXIT_TRACE: + { + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(self); + return frame; + } + + default: + { + fprintf(stderr, "Unknown uop %d, operand %" PRIu64 "\n", opcode, operand); + Py_FatalError("Unknown uop"); + abort(); // Unreachable + for (;;) {} + // Really unreachable + } + + } + } + +pop_4_error: + STACK_SHRINK(1); +pop_3_error: + STACK_SHRINK(1); +pop_2_error: + STACK_SHRINK(1); +pop_1_error: + STACK_SHRINK(1); +error: + // On ERROR_IF we return NULL as the frame. + // The caller recovers the frame from cframe.current_frame. +#ifdef LLTRACE + if (lltrace >= 2) { + fprintf(stderr, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); + } +#endif + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(self); + return NULL; + +PREDICTED(UNPACK_SEQUENCE) +PREDICTED(COMPARE_OP) +PREDICTED(LOAD_SUPER_ATTR) +PREDICTED(STORE_SUBSCR) +PREDICTED(BINARY_SUBSCR) +PREDICTED(BINARY_OP) + // On DEOPT_IF we just repeat the last instruction. + // This presumes nothing was popped from the stack (nor pushed). +#ifdef LLTRACE + if (lltrace >= 2) { + fprintf(stderr, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); + } +#endif + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(self); + return frame; +} diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 706a9a24b26b04..0d41ef5a14cef4 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -1,4 +1,4 @@ -// Macros needed by ceval.c and bytecodes.c +// Macros and other things needed by ceval.c and bytecodes.c /* Computed GOTOs, or the-optimization-commonly-but-improperly-known-as-"threaded code" @@ -339,3 +339,11 @@ do { \ goto error; \ } \ } while (0); + +typedef PyObject *(*convertion_func_ptr)(PyObject *); + +static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = { + [FVC_STR] = PyObject_Str, + [FVC_REPR] = PyObject_Repr, + [FVC_ASCII] = PyObject_ASCII +}; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h new file mode 100644 index 00000000000000..1bdee40d4f8eec --- /dev/null +++ b/Python/executor_cases.c.h @@ -0,0 +1,1606 @@ +// This file is generated by Tools/cases_generator/generate_cases.py +// from: +// Python/bytecodes.c +// Do not edit! + + case NOP: { + break; + } + + case LOAD_FAST: { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + + case LOAD_FAST_AND_CLEAR: { + PyObject *value; + value = GETLOCAL(oparg); + // do not use SETLOCAL here, it decrefs the old value + GETLOCAL(oparg) = NULL; + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + + case LOAD_CONST: { + PyObject *value; + value = GETITEM(FRAME_CO_CONSTS, oparg); + Py_INCREF(value); + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + + case STORE_FAST: { + PyObject *value = stack_pointer[-1]; + SETLOCAL(oparg, value); + STACK_SHRINK(1); + break; + } + + case POP_TOP: { + PyObject *value = stack_pointer[-1]; + Py_DECREF(value); + STACK_SHRINK(1); + break; + } + + case PUSH_NULL: { + PyObject *res; + res = NULL; + STACK_GROW(1); + stack_pointer[-1] = res; + break; + } + + case END_SEND: { + PyObject *value = stack_pointer[-1]; + PyObject *receiver = stack_pointer[-2]; + Py_DECREF(receiver); + STACK_SHRINK(1); + stack_pointer[-1] = value; + break; + } + + case UNARY_NEGATIVE: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + res = PyNumber_Negative(value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + stack_pointer[-1] = res; + break; + } + + case UNARY_NOT: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + int err = PyObject_IsTrue(value); + Py_DECREF(value); + if (err < 0) goto pop_1_error; + if (err == 0) { + res = Py_True; + } + else { + res = Py_False; + } + stack_pointer[-1] = res; + break; + } + + case UNARY_INVERT: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + res = PyNumber_Invert(value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_INT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + break; + } + + case _BINARY_OP_MULTIPLY_INT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_ADD_INT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_SUBTRACT_INT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_FLOAT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + break; + } + + case _BINARY_OP_MULTIPLY_FLOAT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval * + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_ADD_FLOAT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _BINARY_OP_SUBTRACT_FLOAT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + double dres = + ((PyFloatObject *)left)->ob_fval - + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case _GUARD_BOTH_UNICODE: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); + break; + } + + case _BINARY_OP_ADD_UNICODE: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + STAT_INC(BINARY_OP, hit); + res = PyUnicode_Concat(left, right); + _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case BINARY_SLICE: { + PyObject *stop = stack_pointer[-1]; + PyObject *start = stack_pointer[-2]; + PyObject *container = stack_pointer[-3]; + PyObject *res; + PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + // Can't use ERROR_IF() here, because we haven't + // DECREF'ed container yet, and we still own slice. + if (slice == NULL) { + res = NULL; + } + else { + res = PyObject_GetItem(container, slice); + Py_DECREF(slice); + } + Py_DECREF(container); + if (res == NULL) goto pop_3_error; + STACK_SHRINK(2); + stack_pointer[-1] = res; + break; + } + + case STORE_SLICE: { + PyObject *stop = stack_pointer[-1]; + PyObject *start = stack_pointer[-2]; + PyObject *container = stack_pointer[-3]; + PyObject *v = stack_pointer[-4]; + PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + int err; + if (slice == NULL) { + err = 1; + } + else { + err = PyObject_SetItem(container, slice, v); + Py_DECREF(slice); + } + Py_DECREF(v); + Py_DECREF(container); + if (err) goto pop_4_error; + STACK_SHRINK(4); + break; + } + + case BINARY_SUBSCR_LIST_INT: { + PyObject *sub = stack_pointer[-1]; + PyObject *list = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); + DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); + + // Deopt unless 0 <= sub < PyList_Size(list) + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyList_GET_ITEM(list, index); + assert(res != NULL); + Py_INCREF(res); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(list); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case BINARY_SUBSCR_TUPLE_INT: { + PyObject *sub = stack_pointer[-1]; + PyObject *tuple = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); + DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); + + // Deopt unless 0 <= sub < PyTuple_Size(list) + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyTuple_GET_ITEM(tuple, index); + assert(res != NULL); + Py_INCREF(res); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(tuple); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case BINARY_SUBSCR_DICT: { + PyObject *sub = stack_pointer[-1]; + PyObject *dict = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyDict_GetItemWithError(dict, sub); + if (res == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetKeyError(sub); + } + Py_DECREF(dict); + Py_DECREF(sub); + if (true) goto pop_2_error; + } + Py_INCREF(res); // Do this before DECREF'ing dict, sub + Py_DECREF(dict); + Py_DECREF(sub); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case LIST_APPEND: { + PyObject *v = stack_pointer[-1]; + PyObject *list = stack_pointer[-(2 + (oparg-1))]; + if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case SET_ADD: { + PyObject *v = stack_pointer[-1]; + PyObject *set = stack_pointer[-(2 + (oparg-1))]; + int err = PySet_Add(set, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case STORE_SUBSCR_LIST_INT: { + PyObject *sub = stack_pointer[-1]; + PyObject *list = stack_pointer[-2]; + PyObject *value = stack_pointer[-3]; + DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); + DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); + + // Ensure nonnegative, zero-or-one-digit ints. + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); + Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + // Ensure index < len(list) + DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); + STAT_INC(STORE_SUBSCR, hit); + + PyObject *old_value = PyList_GET_ITEM(list, index); + PyList_SET_ITEM(list, index, value); + assert(old_value != NULL); + Py_DECREF(old_value); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(list); + STACK_SHRINK(3); + break; + } + + case STORE_SUBSCR_DICT: { + PyObject *sub = stack_pointer[-1]; + PyObject *dict = stack_pointer[-2]; + PyObject *value = stack_pointer[-3]; + DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); + STAT_INC(STORE_SUBSCR, hit); + int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); + Py_DECREF(dict); + if (err) goto pop_3_error; + STACK_SHRINK(3); + break; + } + + case DELETE_SUBSCR: { + PyObject *sub = stack_pointer[-1]; + PyObject *container = stack_pointer[-2]; + /* del container[sub] */ + int err = PyObject_DelItem(container, sub); + Py_DECREF(container); + Py_DECREF(sub); + if (err) goto pop_2_error; + STACK_SHRINK(2); + break; + } + + case CALL_INTRINSIC_1: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + assert(oparg <= MAX_INTRINSIC_1); + res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + stack_pointer[-1] = res; + break; + } + + case CALL_INTRINSIC_2: { + PyObject *value1 = stack_pointer[-1]; + PyObject *value2 = stack_pointer[-2]; + PyObject *res; + assert(oparg <= MAX_INTRINSIC_2); + res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); + Py_DECREF(value2); + Py_DECREF(value1); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case GET_AITER: { + PyObject *obj = stack_pointer[-1]; + PyObject *iter; + unaryfunc getter = NULL; + PyTypeObject *type = Py_TYPE(obj); + + if (type->tp_as_async != NULL) { + getter = type->tp_as_async->am_aiter; + } + + if (getter == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' requires an object with " + "__aiter__ method, got %.100s", + type->tp_name); + Py_DECREF(obj); + if (true) goto pop_1_error; + } + + iter = (*getter)(obj); + Py_DECREF(obj); + if (iter == NULL) goto pop_1_error; + + if (Py_TYPE(iter)->tp_as_async == NULL || + Py_TYPE(iter)->tp_as_async->am_anext == NULL) { + + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' received an object from __aiter__ " + "that does not implement __anext__: %.100s", + Py_TYPE(iter)->tp_name); + Py_DECREF(iter); + if (true) goto pop_1_error; + } + stack_pointer[-1] = iter; + break; + } + + case GET_ANEXT: { + PyObject *aiter = stack_pointer[-1]; + PyObject *awaitable; + unaryfunc getter = NULL; + PyObject *next_iter = NULL; + PyTypeObject *type = Py_TYPE(aiter); + + if (PyAsyncGen_CheckExact(aiter)) { + awaitable = type->tp_as_async->am_anext(aiter); + if (awaitable == NULL) { + goto error; + } + } else { + if (type->tp_as_async != NULL){ + getter = type->tp_as_async->am_anext; + } + + if (getter != NULL) { + next_iter = (*getter)(aiter); + if (next_iter == NULL) { + goto error; + } + } + else { + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' requires an iterator with " + "__anext__ method, got %.100s", + type->tp_name); + goto error; + } + + awaitable = _PyCoro_GetAwaitableIter(next_iter); + if (awaitable == NULL) { + _PyErr_FormatFromCause( + PyExc_TypeError, + "'async for' received an invalid object " + "from __anext__: %.100s", + Py_TYPE(next_iter)->tp_name); + + Py_DECREF(next_iter); + goto error; + } else { + Py_DECREF(next_iter); + } + } + STACK_GROW(1); + stack_pointer[-1] = awaitable; + break; + } + + case GET_AWAITABLE: { + PyObject *iterable = stack_pointer[-1]; + PyObject *iter; + iter = _PyCoro_GetAwaitableIter(iterable); + + if (iter == NULL) { + format_awaitable_error(tstate, Py_TYPE(iterable), oparg); + } + + Py_DECREF(iterable); + + if (iter != NULL && PyCoro_CheckExact(iter)) { + PyObject *yf = _PyGen_yf((PyGenObject*)iter); + if (yf != NULL) { + /* `iter` is a coroutine object that is being + awaited, `yf` is a pointer to the current awaitable + being awaited on. */ + Py_DECREF(yf); + Py_CLEAR(iter); + _PyErr_SetString(tstate, PyExc_RuntimeError, + "coroutine is being awaited already"); + /* The code below jumps to `error` if `iter` is NULL. */ + } + } + + if (iter == NULL) goto pop_1_error; + stack_pointer[-1] = iter; + break; + } + + case POP_EXCEPT: { + PyObject *exc_value = stack_pointer[-1]; + _PyErr_StackItem *exc_info = tstate->exc_info; + Py_XSETREF(exc_info->exc_value, exc_value); + STACK_SHRINK(1); + break; + } + + case LOAD_ASSERTION_ERROR: { + PyObject *value; + value = Py_NewRef(PyExc_AssertionError); + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + + case LOAD_BUILD_CLASS: { + PyObject *bc; + if (PyDict_CheckExact(BUILTINS())) { + bc = _PyDict_GetItemWithError(BUILTINS(), + &_Py_ID(__build_class__)); + if (bc == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + } + if (true) goto error; + } + Py_INCREF(bc); + } + else { + bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); + if (bc == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + if (true) goto error; + } + } + STACK_GROW(1); + stack_pointer[-1] = bc; + break; + } + + case STORE_NAME: { + PyObject *v = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + PyObject *ns = LOCALS(); + int err; + if (ns == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when storing %R", name); + Py_DECREF(v); + if (true) goto pop_1_error; + } + if (PyDict_CheckExact(ns)) + err = PyDict_SetItem(ns, name, v); + else + err = PyObject_SetItem(ns, name, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case DELETE_NAME: { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + PyObject *ns = LOCALS(); + int err; + if (ns == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals when deleting %R", name); + goto error; + } + err = PyObject_DelItem(ns, name); + // Can't use ERROR_IF here. + if (err != 0) { + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, + name); + goto error; + } + break; + } + + case UNPACK_SEQUENCE_TWO_TUPLE: { + PyObject *seq = stack_pointer[-1]; + PyObject **values = stack_pointer - (1); + DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); + assert(oparg == 2); + STAT_INC(UNPACK_SEQUENCE, hit); + values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); + values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); + Py_DECREF(seq); + STACK_SHRINK(1); + STACK_GROW(oparg); + break; + } + + case UNPACK_SEQUENCE_TUPLE: { + PyObject *seq = stack_pointer[-1]; + PyObject **values = stack_pointer - (1); + DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); + STAT_INC(UNPACK_SEQUENCE, hit); + PyObject **items = _PyTuple_ITEMS(seq); + for (int i = oparg; --i >= 0; ) { + *values++ = Py_NewRef(items[i]); + } + Py_DECREF(seq); + STACK_SHRINK(1); + STACK_GROW(oparg); + break; + } + + case UNPACK_SEQUENCE_LIST: { + PyObject *seq = stack_pointer[-1]; + PyObject **values = stack_pointer - (1); + DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); + STAT_INC(UNPACK_SEQUENCE, hit); + PyObject **items = _PyList_ITEMS(seq); + for (int i = oparg; --i >= 0; ) { + *values++ = Py_NewRef(items[i]); + } + Py_DECREF(seq); + STACK_SHRINK(1); + STACK_GROW(oparg); + break; + } + + case UNPACK_EX: { + PyObject *seq = stack_pointer[-1]; + int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); + PyObject **top = stack_pointer + totalargs - 1; + int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); + Py_DECREF(seq); + if (res == 0) goto pop_1_error; + STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + break; + } + + case DELETE_ATTR: { + PyObject *owner = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + Py_DECREF(owner); + if (err) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case STORE_GLOBAL: { + PyObject *v = stack_pointer[-1]; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + int err = PyDict_SetItem(GLOBALS(), name, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case DELETE_GLOBAL: { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + int err; + err = PyDict_DelItem(GLOBALS(), name); + // Can't use ERROR_IF here. + if (err != 0) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + break; + } + + case _LOAD_LOCALS: { + PyObject *locals; + locals = LOCALS(); + if (locals == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, + "no locals found"); + if (true) goto error; + } + Py_INCREF(locals); + STACK_GROW(1); + stack_pointer[-1] = locals; + break; + } + + case _LOAD_FROM_DICT_OR_GLOBALS: { + PyObject *mod_or_class_dict = stack_pointer[-1]; + PyObject *v; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + if (PyDict_CheckExact(mod_or_class_dict)) { + v = PyDict_GetItemWithError(mod_or_class_dict, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + Py_DECREF(mod_or_class_dict); + goto error; + } + } + else { + v = PyObject_GetItem(mod_or_class_dict, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(mod_or_class_dict); + goto error; + } + _PyErr_Clear(tstate); + } + } + Py_DECREF(mod_or_class_dict); + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + else { + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + } + } + } + stack_pointer[-1] = v; + break; + } + + case DELETE_DEREF: { + PyObject *cell = GETLOCAL(oparg); + PyObject *oldobj = PyCell_GET(cell); + // Can't use ERROR_IF here. + // Fortunately we don't need its superpower. + if (oldobj == NULL) { + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); + goto error; + } + PyCell_SET(cell, NULL); + Py_DECREF(oldobj); + break; + } + + case LOAD_FROM_DICT_OR_DEREF: { + PyObject *class_dict = stack_pointer[-1]; + PyObject *value; + PyObject *name; + assert(class_dict); + assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); + name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); + if (PyDict_CheckExact(class_dict)) { + value = PyDict_GetItemWithError(class_dict, name); + if (value != NULL) { + Py_INCREF(value); + } + else if (_PyErr_Occurred(tstate)) { + Py_DECREF(class_dict); + goto error; + } + } + else { + value = PyObject_GetItem(class_dict, name); + if (value == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + Py_DECREF(class_dict); + goto error; + } + _PyErr_Clear(tstate); + } + } + Py_DECREF(class_dict); + if (!value) { + PyObject *cell = GETLOCAL(oparg); + value = PyCell_GET(cell); + if (value == NULL) { + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); + goto error; + } + Py_INCREF(value); + } + stack_pointer[-1] = value; + break; + } + + case LOAD_DEREF: { + PyObject *value; + PyObject *cell = GETLOCAL(oparg); + value = PyCell_GET(cell); + if (value == NULL) { + format_exc_unbound(tstate, _PyFrame_GetCode(frame), oparg); + if (true) goto error; + } + Py_INCREF(value); + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + + case STORE_DEREF: { + PyObject *v = stack_pointer[-1]; + PyObject *cell = GETLOCAL(oparg); + PyObject *oldobj = PyCell_GET(cell); + PyCell_SET(cell, v); + Py_XDECREF(oldobj); + STACK_SHRINK(1); + break; + } + + case COPY_FREE_VARS: { + /* Copy closure variables to free variables */ + PyCodeObject *co = _PyFrame_GetCode(frame); + assert(PyFunction_Check(frame->f_funcobj)); + PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; + assert(oparg == co->co_nfreevars); + int offset = co->co_nlocalsplus - oparg; + for (int i = 0; i < oparg; ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + frame->localsplus[offset + i] = Py_NewRef(o); + } + break; + } + + case BUILD_STRING: { + PyObject **pieces = (stack_pointer - oparg); + PyObject *str; + str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(pieces[_i]); + } + if (str == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + stack_pointer[-1] = str; + break; + } + + case BUILD_TUPLE: { + PyObject **values = (stack_pointer - oparg); + PyObject *tup; + tup = _PyTuple_FromArraySteal(values, oparg); + if (tup == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + stack_pointer[-1] = tup; + break; + } + + case BUILD_LIST: { + PyObject **values = (stack_pointer - oparg); + PyObject *list; + list = _PyList_FromArraySteal(values, oparg); + if (list == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + stack_pointer[-1] = list; + break; + } + + case LIST_EXTEND: { + PyObject *iterable = stack_pointer[-1]; + PyObject *list = stack_pointer[-(2 + (oparg-1))]; + PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); + if (none_val == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && + (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) + { + _PyErr_Clear(tstate); + _PyErr_Format(tstate, PyExc_TypeError, + "Value after * must be an iterable, not %.200s", + Py_TYPE(iterable)->tp_name); + } + Py_DECREF(iterable); + if (true) goto pop_1_error; + } + assert(Py_IsNone(none_val)); + Py_DECREF(iterable); + STACK_SHRINK(1); + break; + } + + case SET_UPDATE: { + PyObject *iterable = stack_pointer[-1]; + PyObject *set = stack_pointer[-(2 + (oparg-1))]; + int err = _PySet_Update(set, iterable); + Py_DECREF(iterable); + if (err < 0) goto pop_1_error; + STACK_SHRINK(1); + break; + } + + case BUILD_SET: { + PyObject **values = (stack_pointer - oparg); + PyObject *set; + set = PySet_New(NULL); + if (set == NULL) + goto error; + int err = 0; + for (int i = 0; i < oparg; i++) { + PyObject *item = values[i]; + if (err == 0) + err = PySet_Add(set, item); + Py_DECREF(item); + } + if (err != 0) { + Py_DECREF(set); + if (true) { STACK_SHRINK(oparg); goto error; } + } + STACK_SHRINK(oparg); + STACK_GROW(1); + stack_pointer[-1] = set; + break; + } + + case BUILD_MAP: { + PyObject **values = (stack_pointer - oparg*2); + PyObject *map; + map = _PyDict_FromItems( + values, 2, + values+1, 2, + oparg); + if (map == NULL) + goto error; + + for (int _i = oparg*2; --_i >= 0;) { + Py_DECREF(values[_i]); + } + if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } + STACK_SHRINK(oparg*2); + STACK_GROW(1); + stack_pointer[-1] = map; + break; + } + + case SETUP_ANNOTATIONS: { + int err; + PyObject *ann_dict; + if (LOCALS() == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when setting up annotations"); + if (true) goto error; + } + /* check if __annotations__ in locals()... */ + if (PyDict_CheckExact(LOCALS())) { + ann_dict = _PyDict_GetItemWithError(LOCALS(), + &_Py_ID(__annotations__)); + if (ann_dict == NULL) { + if (_PyErr_Occurred(tstate)) goto error; + /* ...if not, create a new one */ + ann_dict = PyDict_New(); + if (ann_dict == NULL) goto error; + err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); + Py_DECREF(ann_dict); + if (err) goto error; + } + } + else { + /* do the same if locals() is not a dict */ + ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); + if (ann_dict == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; + _PyErr_Clear(tstate); + ann_dict = PyDict_New(); + if (ann_dict == NULL) goto error; + err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); + Py_DECREF(ann_dict); + if (err) goto error; + } + else { + Py_DECREF(ann_dict); + } + } + break; + } + + case BUILD_CONST_KEY_MAP: { + PyObject *keys = stack_pointer[-1]; + PyObject **values = (stack_pointer - (1 + oparg)); + PyObject *map; + if (!PyTuple_CheckExact(keys) || + PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { + _PyErr_SetString(tstate, PyExc_SystemError, + "bad BUILD_CONST_KEY_MAP keys argument"); + goto error; // Pop the keys and values. + } + map = _PyDict_FromItems( + &PyTuple_GET_ITEM(keys, 0), 1, + values, 1, oparg); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(values[_i]); + } + Py_DECREF(keys); + if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } + STACK_SHRINK(oparg); + stack_pointer[-1] = map; + break; + } + + case DICT_UPDATE: { + PyObject *update = stack_pointer[-1]; + PyObject *dict = PEEK(oparg + 1); // update is still on the stack + if (PyDict_Update(dict, update) < 0) { + if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not a mapping", + Py_TYPE(update)->tp_name); + } + Py_DECREF(update); + if (true) goto pop_1_error; + } + Py_DECREF(update); + STACK_SHRINK(1); + break; + } + + case DICT_MERGE: { + PyObject *update = stack_pointer[-1]; + PyObject *dict = PEEK(oparg + 1); // update is still on the stack + + if (_PyDict_MergeEx(dict, update, 2) < 0) { + format_kwargs_error(tstate, PEEK(3 + oparg), update); + Py_DECREF(update); + if (true) goto pop_1_error; + } + Py_DECREF(update); + STACK_SHRINK(1); + break; + } + + case MAP_ADD: { + PyObject *value = stack_pointer[-1]; + PyObject *key = stack_pointer[-2]; + PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack + assert(PyDict_CheckExact(dict)); + /* dict[key] = value */ + // Do not DECREF INPUTS because the function steals the references + if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; + STACK_SHRINK(2); + break; + } + + case LOAD_SUPER_ATTR_ATTR: { + PyObject *self = stack_pointer[-1]; + PyObject *class = stack_pointer[-2]; + PyObject *global_super = stack_pointer[-3]; + PyObject *res2 = NULL; + PyObject *res; + assert(!(oparg & 1)); + DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); + DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + Py_DECREF(global_super); + Py_DECREF(class); + Py_DECREF(self); + if (res == NULL) goto pop_3_error; + STACK_SHRINK(2); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + break; + } + + case LOAD_SUPER_ATTR_METHOD: { + PyObject *self = stack_pointer[-1]; + PyObject *class = stack_pointer[-2]; + PyObject *global_super = stack_pointer[-3]; + PyObject *res2; + PyObject *res; + assert(oparg & 1); + DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); + DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); + STAT_INC(LOAD_SUPER_ATTR, hit); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + PyTypeObject *cls = (PyTypeObject *)class; + int method_found = 0; + res2 = _PySuper_Lookup(cls, self, name, + cls->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); + Py_DECREF(global_super); + Py_DECREF(class); + if (res2 == NULL) { + Py_DECREF(self); + if (true) goto pop_3_error; + } + if (method_found) { + res = self; // transfer ownership + } else { + Py_DECREF(self); + res = res2; + res2 = NULL; + } + STACK_SHRINK(1); + stack_pointer[-1] = res; + stack_pointer[-2] = res2; + break; + } + + case COMPARE_OP_FLOAT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + double dleft = PyFloat_AS_DOUBLE(left); + double dright = PyFloat_AS_DOUBLE(right); + // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg + int sign_ish = COMPARISON_BIT(dleft, dright); + _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); + res = (sign_ish & oparg) ? Py_True : Py_False; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case COMPARE_OP_INT: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); + // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg + int sign_ish = COMPARISON_BIT(ileft, iright); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + res = (sign_ish & oparg) ? Py_True : Py_False; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case COMPARE_OP_STR: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); + assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + assert(eq == 0 || eq == 1); + assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); + assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case IS_OP: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *b; + int res = Py_Is(left, right) ^ oparg; + Py_DECREF(left); + Py_DECREF(right); + b = res ? Py_True : Py_False; + STACK_SHRINK(1); + stack_pointer[-1] = b; + break; + } + + case CONTAINS_OP: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *b; + int res = PySequence_Contains(right, left); + Py_DECREF(left); + Py_DECREF(right); + if (res < 0) goto pop_2_error; + b = (res ^ oparg) ? Py_True : Py_False; + STACK_SHRINK(1); + stack_pointer[-1] = b; + break; + } + + case CHECK_EG_MATCH: { + PyObject *match_type = stack_pointer[-1]; + PyObject *exc_value = stack_pointer[-2]; + PyObject *rest; + PyObject *match; + if (check_except_star_type_valid(tstate, match_type) < 0) { + Py_DECREF(exc_value); + Py_DECREF(match_type); + if (true) goto pop_2_error; + } + + match = NULL; + rest = NULL; + int res = exception_group_match(exc_value, match_type, + &match, &rest); + Py_DECREF(exc_value); + Py_DECREF(match_type); + if (res < 0) goto pop_2_error; + + assert((match == NULL) == (rest == NULL)); + if (match == NULL) goto pop_2_error; + + if (!Py_IsNone(match)) { + PyErr_SetHandledException(match); + } + stack_pointer[-1] = match; + stack_pointer[-2] = rest; + break; + } + + case CHECK_EXC_MATCH: { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *b; + assert(PyExceptionInstance_Check(left)); + if (check_except_type_valid(tstate, right) < 0) { + Py_DECREF(right); + if (true) goto pop_1_error; + } + + int res = PyErr_GivenExceptionMatches(left, right); + Py_DECREF(right); + b = res ? Py_True : Py_False; + stack_pointer[-1] = b; + break; + } + + case GET_LEN: { + PyObject *obj = stack_pointer[-1]; + PyObject *len_o; + // PUSH(len(TOS)) + Py_ssize_t len_i = PyObject_Length(obj); + if (len_i < 0) goto error; + len_o = PyLong_FromSsize_t(len_i); + if (len_o == NULL) goto error; + STACK_GROW(1); + stack_pointer[-1] = len_o; + break; + } + + case MATCH_CLASS: { + PyObject *names = stack_pointer[-1]; + PyObject *type = stack_pointer[-2]; + PyObject *subject = stack_pointer[-3]; + PyObject *attrs; + // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or + // None on failure. + assert(PyTuple_CheckExact(names)); + attrs = match_class(tstate, subject, type, oparg, names); + Py_DECREF(subject); + Py_DECREF(type); + Py_DECREF(names); + if (attrs) { + assert(PyTuple_CheckExact(attrs)); // Success! + } + else { + if (_PyErr_Occurred(tstate)) goto pop_3_error; + attrs = Py_None; // Failure! + } + STACK_SHRINK(2); + stack_pointer[-1] = attrs; + break; + } + + case MATCH_MAPPING: { + PyObject *subject = stack_pointer[-1]; + PyObject *res; + int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; + res = match ? Py_True : Py_False; + STACK_GROW(1); + stack_pointer[-1] = res; + break; + } + + case MATCH_SEQUENCE: { + PyObject *subject = stack_pointer[-1]; + PyObject *res; + int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; + res = match ? Py_True : Py_False; + STACK_GROW(1); + stack_pointer[-1] = res; + break; + } + + case MATCH_KEYS: { + PyObject *keys = stack_pointer[-1]; + PyObject *subject = stack_pointer[-2]; + PyObject *values_or_none; + // On successful match, PUSH(values). Otherwise, PUSH(None). + values_or_none = match_keys(tstate, subject, keys); + if (values_or_none == NULL) goto error; + STACK_GROW(1); + stack_pointer[-1] = values_or_none; + break; + } + + case GET_ITER: { + PyObject *iterable = stack_pointer[-1]; + PyObject *iter; + /* before: [obj]; after [getiter(obj)] */ + iter = PyObject_GetIter(iterable); + Py_DECREF(iterable); + if (iter == NULL) goto pop_1_error; + stack_pointer[-1] = iter; + break; + } + + case GET_YIELD_FROM_ITER: { + PyObject *iterable = stack_pointer[-1]; + PyObject *iter; + /* before: [obj]; after [getiter(obj)] */ + if (PyCoro_CheckExact(iterable)) { + /* `iterable` is a coroutine */ + if (!(_PyFrame_GetCode(frame)->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { + /* and it is used in a 'yield from' expression of a + regular generator. */ + _PyErr_SetString(tstate, PyExc_TypeError, + "cannot 'yield from' a coroutine object " + "in a non-coroutine generator"); + goto error; + } + iter = iterable; + } + else if (PyGen_CheckExact(iterable)) { + iter = iterable; + } + else { + /* `iterable` is not a generator. */ + iter = PyObject_GetIter(iterable); + if (iter == NULL) { + goto error; + } + Py_DECREF(iterable); + } + stack_pointer[-1] = iter; + break; + } + + case WITH_EXCEPT_START: { + PyObject *val = stack_pointer[-1]; + PyObject *lasti = stack_pointer[-3]; + PyObject *exit_func = stack_pointer[-4]; + PyObject *res; + /* At the top of the stack are 4 values: + - val: TOP = exc_info() + - unused: SECOND = previous exception + - lasti: THIRD = lasti of exception in exc_info() + - exit_func: FOURTH = the context.__exit__ bound method + We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). + Then we push the __exit__ return value. + */ + PyObject *exc, *tb; + + assert(val && PyExceptionInstance_Check(val)); + exc = PyExceptionInstance_Class(val); + tb = PyException_GetTraceback(val); + Py_XDECREF(tb); + assert(PyLong_Check(lasti)); + (void)lasti; // Shut up compiler warning if asserts are off + PyObject *stack[4] = {NULL, exc, val, tb}; + res = PyObject_Vectorcall(exit_func, stack + 1, + 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + if (res == NULL) goto error; + STACK_GROW(1); + stack_pointer[-1] = res; + break; + } + + case PUSH_EXC_INFO: { + PyObject *new_exc = stack_pointer[-1]; + PyObject *prev_exc; + _PyErr_StackItem *exc_info = tstate->exc_info; + if (exc_info->exc_value != NULL) { + prev_exc = exc_info->exc_value; + } + else { + prev_exc = Py_None; + } + assert(PyExceptionInstance_Check(new_exc)); + exc_info->exc_value = Py_NewRef(new_exc); + STACK_GROW(1); + stack_pointer[-1] = new_exc; + stack_pointer[-2] = prev_exc; + break; + } + + case EXIT_INIT_CHECK: { + PyObject *should_be_none = stack_pointer[-1]; + assert(STACK_LEVEL() == 2); + if (should_be_none != Py_None) { + PyErr_Format(PyExc_TypeError, + "__init__() should return None, not '%.200s'", + Py_TYPE(should_be_none)->tp_name); + goto error; + } + STACK_SHRINK(1); + break; + } + + case MAKE_FUNCTION: { + PyObject *codeobj = stack_pointer[-1]; + PyObject *func; + + PyFunctionObject *func_obj = (PyFunctionObject *) + PyFunction_New(codeobj, GLOBALS()); + + Py_DECREF(codeobj); + if (func_obj == NULL) { + goto error; + } + + func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; + func = (PyObject *)func_obj; + stack_pointer[-1] = func; + break; + } + + case SET_FUNCTION_ATTRIBUTE: { + PyObject *func = stack_pointer[-1]; + PyObject *attr = stack_pointer[-2]; + assert(PyFunction_Check(func)); + PyFunctionObject *func_obj = (PyFunctionObject *)func; + switch(oparg) { + case MAKE_FUNCTION_CLOSURE: + assert(func_obj->func_closure == NULL); + func_obj->func_closure = attr; + break; + case MAKE_FUNCTION_ANNOTATIONS: + assert(func_obj->func_annotations == NULL); + func_obj->func_annotations = attr; + break; + case MAKE_FUNCTION_KWDEFAULTS: + assert(PyDict_CheckExact(attr)); + assert(func_obj->func_kwdefaults == NULL); + func_obj->func_kwdefaults = attr; + break; + case MAKE_FUNCTION_DEFAULTS: + assert(PyTuple_CheckExact(attr)); + assert(func_obj->func_defaults == NULL); + func_obj->func_defaults = attr; + break; + default: + Py_UNREACHABLE(); + } + STACK_SHRINK(1); + stack_pointer[-1] = func; + break; + } + + case BUILD_SLICE: { + PyObject *step = (oparg == 3) ? stack_pointer[-(((oparg == 3) ? 1 : 0))] : NULL; + PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; + PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; + PyObject *slice; + slice = PySlice_New(start, stop, step); + Py_DECREF(start); + Py_DECREF(stop); + Py_XDECREF(step); + if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } + STACK_SHRINK(((oparg == 3) ? 1 : 0)); + STACK_SHRINK(1); + stack_pointer[-1] = slice; + break; + } + + case CONVERT_VALUE: { + PyObject *value = stack_pointer[-1]; + PyObject *result; + convertion_func_ptr conv_fn; + assert(oparg >= FVC_STR && oparg <= FVC_ASCII); + conv_fn = CONVERSION_FUNCTIONS[oparg]; + result = conv_fn(value); + Py_DECREF(value); + if (result == NULL) goto pop_1_error; + stack_pointer[-1] = result; + break; + } + + case FORMAT_SIMPLE: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + /* If value is a unicode object, then we know the result + * of format(value) is value itself. */ + if (!PyUnicode_CheckExact(value)) { + res = PyObject_Format(value, NULL); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + } + else { + res = value; + } + stack_pointer[-1] = res; + break; + } + + case FORMAT_WITH_SPEC: { + PyObject *fmt_spec = stack_pointer[-1]; + PyObject *value = stack_pointer[-2]; + PyObject *res; + res = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_DECREF(fmt_spec); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case COPY: { + PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; + PyObject *top; + assert(oparg > 0); + top = Py_NewRef(bottom); + STACK_GROW(1); + stack_pointer[-1] = top; + break; + } + + case SWAP: { + PyObject *top = stack_pointer[-1]; + PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; + assert(oparg >= 2); + stack_pointer[-1] = bottom; + stack_pointer[-(2 + (oparg-2))] = top; + break; + } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 11ca535adfb19b..43cfd4a882c73a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 139 "Python/bytecodes.c" + #line 137 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 153 "Python/bytecodes.c" + #line 151 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? @@ -57,7 +57,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 181 "Python/bytecodes.c" + #line 179 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -70,7 +70,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 188 "Python/bytecodes.c" + #line 186 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -82,7 +82,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 194 "Python/bytecodes.c" + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 200 "Python/bytecodes.c" + #line 198 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -107,7 +107,7 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 206 "Python/bytecodes.c" + #line 204 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); @@ -123,7 +123,7 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 215 "Python/bytecodes.c" + #line 213 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 130 "Python/generated_cases.c.h" @@ -134,7 +134,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 220 "Python/bytecodes.c" + #line 218 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 140 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -144,7 +144,7 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 228 "Python/bytecodes.c" + #line 226 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -158,7 +158,7 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 236 "Python/bytecodes.c" + #line 234 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -170,7 +170,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 243 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 175 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -179,7 +179,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 247 "Python/bytecodes.c" + #line 245 "Python/bytecodes.c" res = NULL; #line 185 "Python/generated_cases.c.h" STACK_GROW(1); @@ -192,13 +192,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 243 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 197 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 243 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" #line 203 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -209,7 +209,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 253 "Python/bytecodes.c" + #line 251 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -229,7 +229,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 266 "Python/bytecodes.c" + #line 264 "Python/bytecodes.c" Py_DECREF(receiver); #line 235 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -240,7 +240,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 270 "Python/bytecodes.c" + #line 268 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -258,11 +258,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 281 "Python/bytecodes.c" + #line 279 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 264 "Python/generated_cases.c.h" Py_DECREF(value); - #line 283 "Python/bytecodes.c" + #line 281 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 268 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -272,11 +272,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 287 "Python/bytecodes.c" + #line 285 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 278 "Python/generated_cases.c.h" Py_DECREF(value); - #line 289 "Python/bytecodes.c" + #line 287 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -292,11 +292,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 299 "Python/bytecodes.c" + #line 297 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 298 "Python/generated_cases.c.h" Py_DECREF(value); - #line 301 "Python/bytecodes.c" + #line 299 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 302 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -309,7 +309,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 317 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 316 "Python/generated_cases.c.h" @@ -320,7 +320,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 322 "Python/bytecodes.c" + #line 320 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -341,7 +341,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 317 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 348 "Python/generated_cases.c.h" @@ -352,7 +352,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 330 "Python/bytecodes.c" + #line 328 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -373,7 +373,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 317 "Python/bytecodes.c" + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 380 "Python/generated_cases.c.h" @@ -384,7 +384,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 338 "Python/bytecodes.c" + #line 336 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -405,7 +405,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 353 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 412 "Python/generated_cases.c.h" @@ -416,7 +416,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 358 "Python/bytecodes.c" + #line 356 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -437,7 +437,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 353 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 444 "Python/generated_cases.c.h" @@ -448,7 +448,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 366 "Python/bytecodes.c" + #line 364 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -469,7 +469,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 353 "Python/bytecodes.c" + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 476 "Python/generated_cases.c.h" @@ -480,7 +480,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 374 "Python/bytecodes.c" + #line 372 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -501,7 +501,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 389 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 508 "Python/generated_cases.c.h" @@ -512,7 +512,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 394 "Python/bytecodes.c" + #line 392 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -533,7 +533,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 389 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 540 "Python/generated_cases.c.h" @@ -543,7 +543,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 411 "Python/bytecodes.c" + #line 409 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -579,7 +579,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 448 "Python/bytecodes.c" + #line 446 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -594,7 +594,7 @@ #line 595 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 460 "Python/bytecodes.c" + #line 458 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 600 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -608,7 +608,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 464 "Python/bytecodes.c" + #line 462 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -632,7 +632,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 479 "Python/bytecodes.c" + #line 477 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -654,7 +654,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 494 "Python/bytecodes.c" + #line 492 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -679,7 +679,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 510 "Python/bytecodes.c" + #line 508 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -704,7 +704,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 526 "Python/bytecodes.c" + #line 524 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -715,7 +715,7 @@ #line 716 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 534 "Python/bytecodes.c" + #line 532 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -731,7 +731,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 541 "Python/bytecodes.c" + #line 539 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -760,7 +760,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 566 "Python/bytecodes.c" + #line 564 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -770,11 +770,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 570 "Python/bytecodes.c" + #line 568 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 776 "Python/generated_cases.c.h" Py_DECREF(v); - #line 572 "Python/bytecodes.c" + #line 570 "Python/bytecodes.c" if (err) goto pop_1_error; #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -788,7 +788,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 582 "Python/bytecodes.c" + #line 580 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -807,7 +807,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 597 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" if (err) goto pop_3_error; #line 813 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -819,7 +819,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 601 "Python/bytecodes.c" + #line 599 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -846,7 +846,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 620 "Python/bytecodes.c" + #line 618 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -861,13 +861,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 628 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 868 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 631 "Python/bytecodes.c" + #line 629 "Python/bytecodes.c" if (err) goto pop_2_error; #line 873 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -877,12 +877,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 635 "Python/bytecodes.c" + #line 633 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 884 "Python/generated_cases.c.h" Py_DECREF(value); - #line 638 "Python/bytecodes.c" + #line 636 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 888 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -893,13 +893,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 642 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 900 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 645 "Python/bytecodes.c" + #line 643 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 905 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -909,7 +909,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 649 "Python/bytecodes.c" + #line 647 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -932,7 +932,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 669 "Python/bytecodes.c" + #line 667 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -946,7 +946,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 680 "Python/bytecodes.c" + #line 678 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -964,7 +964,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 695 "Python/bytecodes.c" + #line 693 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -985,7 +985,7 @@ } TARGET(RETURN_CONST) { - #line 714 "Python/bytecodes.c" + #line 712 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1003,7 +1003,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 730 "Python/bytecodes.c" + #line 728 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1027,7 +1027,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 750 "Python/bytecodes.c" + #line 748 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1042,14 +1042,14 @@ type->tp_name); #line 1044 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 763 "Python/bytecodes.c" + #line 761 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1051 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 768 "Python/bytecodes.c" + #line 766 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1070,7 +1070,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 783 "Python/bytecodes.c" + #line 781 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1122,7 +1122,7 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 828 "Python/bytecodes.c" + #line 826 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1131,7 +1131,7 @@ #line 1133 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 835 "Python/bytecodes.c" + #line 833 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1159,7 +1159,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 859 "Python/bytecodes.c" + #line 857 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1215,7 +1215,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 908 "Python/bytecodes.c" + #line 906 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1236,7 +1236,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 926 "Python/bytecodes.c" + #line 924 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1259,7 +1259,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 946 "Python/bytecodes.c" + #line 944 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1281,7 +1281,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 965 "Python/bytecodes.c" + #line 963 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1288 "Python/generated_cases.c.h" @@ -1292,7 +1292,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 970 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1316,13 +1316,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 990 "Python/bytecodes.c" + #line 988 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1323 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 993 "Python/bytecodes.c" + #line 991 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1340,7 +1340,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1002 "Python/bytecodes.c" + #line 1000 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1349,7 +1349,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1007 "Python/bytecodes.c" + #line 1005 "Python/bytecodes.c" none = Py_None; } else { @@ -1365,7 +1365,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1016 "Python/bytecodes.c" + #line 1014 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1371 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1375,7 +1375,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1020 "Python/bytecodes.c" + #line 1018 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1405,7 +1405,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1045 "Python/bytecodes.c" + #line 1043 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1414,7 +1414,7 @@ "no locals found when storing %R", name); #line 1416 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1052 "Python/bytecodes.c" + #line 1050 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1423,7 +1423,7 @@ err = PyObject_SetItem(ns, name, v); #line 1425 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1059 "Python/bytecodes.c" + #line 1057 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1429 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1431,7 +1431,7 @@ } TARGET(DELETE_NAME) { - #line 1063 "Python/bytecodes.c" + #line 1061 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1456,7 +1456,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1089 "Python/bytecodes.c" + #line 1087 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1471,7 +1471,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1473 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1102 "Python/bytecodes.c" + #line 1100 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1477 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1483,7 +1483,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1106 "Python/bytecodes.c" + #line 1104 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1501,7 +1501,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1116 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1520,7 +1520,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1127 "Python/bytecodes.c" + #line 1125 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1538,13 +1538,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1138 "Python/bytecodes.c" + #line 1136 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1546 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1142 "Python/bytecodes.c" + #line 1140 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1550 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1557,7 +1557,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1153 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1576,7 +1576,7 @@ #line 1577 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1169 "Python/bytecodes.c" + #line 1167 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1582 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1586,12 +1586,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1173 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1593 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1176 "Python/bytecodes.c" + #line 1174 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1597 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1600,12 +1600,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1180 "Python/bytecodes.c" + #line 1178 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1607 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1183 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1611 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1613,7 +1613,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1187 "Python/bytecodes.c" + #line 1185 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1633,7 +1633,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1201 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1653,7 +1653,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1201 "Python/bytecodes.c" + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1667,7 +1667,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1213 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1737,7 +1737,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1213 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1806,7 +1806,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1282 "Python/bytecodes.c" + #line 1280 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1872,7 +1872,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1336 "Python/bytecodes.c" + #line 1334 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1898,7 +1898,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1349 "Python/bytecodes.c" + #line 1347 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1923,7 +1923,7 @@ } TARGET(DELETE_FAST) { - #line 1366 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1932,7 +1932,7 @@ } TARGET(MAKE_CELL) { - #line 1372 "Python/bytecodes.c" + #line 1370 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1946,7 +1946,7 @@ } TARGET(DELETE_DEREF) { - #line 1383 "Python/bytecodes.c" + #line 1381 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1964,7 +1964,7 @@ TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1396 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -2006,7 +2006,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1433 "Python/bytecodes.c" + #line 1431 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2022,7 +2022,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1443 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -2033,7 +2033,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1450 "Python/bytecodes.c" + #line 1448 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2051,13 +2051,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1463 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2057 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1465 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2069,7 +2069,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1469 "Python/bytecodes.c" + #line 1467 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2076 "Python/generated_cases.c.h" @@ -2082,7 +2082,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1474 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2089 "Python/generated_cases.c.h" @@ -2095,7 +2095,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1479 "Python/bytecodes.c" + #line 1477 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2108,7 +2108,7 @@ } #line 2110 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1490 "Python/bytecodes.c" + #line 1488 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -2121,11 +2121,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1497 "Python/bytecodes.c" + #line 1495 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2127 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1499 "Python/bytecodes.c" + #line 1497 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2131 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2135,7 +2135,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1503 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2160,7 +2160,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1520 "Python/bytecodes.c" + #line 1518 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2172,7 +2172,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1528 "Python/bytecodes.c" + #line 1526 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2178 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -2182,7 +2182,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1532 "Python/bytecodes.c" + #line 1530 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2230,7 +2230,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1574 "Python/bytecodes.c" + #line 1572 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2245,7 +2245,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1584 "Python/bytecodes.c" + #line 1582 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2251 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2255,7 +2255,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1588 "Python/bytecodes.c" + #line 1586 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2265,7 +2265,7 @@ } #line 2267 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1596 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2272 "Python/generated_cases.c.h" @@ -2276,14 +2276,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1602 "Python/bytecodes.c" + #line 1600 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2285 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1607 "Python/bytecodes.c" + #line 1605 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2290 "Python/generated_cases.c.h" @@ -2295,7 +2295,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1613 "Python/bytecodes.c" + #line 1611 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2307,7 +2307,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1621 "Python/bytecodes.c" + #line 1619 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -2324,7 +2324,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1635 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2370,7 +2370,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1677 "Python/bytecodes.c" + #line 1675 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2390,7 +2390,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1696 "Python/bytecodes.c" + #line 1694 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2401,7 +2401,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1703 "Python/bytecodes.c" + #line 1701 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2407 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -2418,7 +2418,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1707 "Python/bytecodes.c" + #line 1705 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2455,7 +2455,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1746 "Python/bytecodes.c" + #line 1744 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2491,7 +2491,7 @@ */ #line 2493 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1780 "Python/bytecodes.c" + #line 1778 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2502,7 +2502,7 @@ res = PyObject_GetAttr(owner, name); #line 2504 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1789 "Python/bytecodes.c" + #line 1787 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2509 "Python/generated_cases.c.h" @@ -2519,7 +2519,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1798 "Python/bytecodes.c" + #line 1796 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2547,7 +2547,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1814 "Python/bytecodes.c" + #line 1812 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2575,7 +2575,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1830 "Python/bytecodes.c" + #line 1828 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2617,7 +2617,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1860 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2642,7 +2642,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1873 "Python/bytecodes.c" + #line 1871 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2668,7 +2668,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1888 "Python/bytecodes.c" + #line 1886 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2700,7 +2700,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1914 "Python/bytecodes.c" + #line 1912 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2734,7 +2734,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1942 "Python/bytecodes.c" + #line 1940 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2763,7 +2763,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1962 "Python/bytecodes.c" + #line 1960 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2813,7 +2813,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2003 "Python/bytecodes.c" + #line 2001 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2835,7 +2835,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2022 "Python/bytecodes.c" + #line 2020 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2851,7 +2851,7 @@ #line 2852 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2035 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2857 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2864,7 +2864,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2039 "Python/bytecodes.c" + #line 2037 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2886,7 +2886,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2053 "Python/bytecodes.c" + #line 2051 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2912,7 +2912,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2071 "Python/bytecodes.c" + #line 2069 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2935,12 +2935,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2085 "Python/bytecodes.c" + #line 2083 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2941 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2087 "Python/bytecodes.c" + #line 2085 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 2946 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2952,12 +2952,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2091 "Python/bytecodes.c" + #line 2089 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2958 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2093 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 2964 "Python/generated_cases.c.h" @@ -2971,12 +2971,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2098 "Python/bytecodes.c" + #line 2096 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2977 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2100 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2987,7 +2987,7 @@ #line 2988 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2108 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3006,19 +3006,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2119 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3013 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2122 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3020 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2127 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3024 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3029,13 +3029,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2131 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3036 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2134 "Python/bytecodes.c" + #line 2132 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3046,7 +3046,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2138 "Python/bytecodes.c" + #line 2136 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3057,14 +3057,14 @@ } TARGET(JUMP_FORWARD) { - #line 2144 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" JUMPBY(oparg); #line 3063 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2148 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3088,14 +3088,14 @@ } TARGET(ENTER_EXECUTOR) { - #line 2179 "Python/bytecodes.c" + #line 2177 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; - goto error; + goto resume_with_error; } goto resume_frame; #line 3102 "Python/generated_cases.c.h" @@ -3103,7 +3103,7 @@ TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2191 "Python/bytecodes.c" + #line 2189 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } @@ -3111,7 +3111,7 @@ int err = PyObject_IsTrue(cond); #line 3113 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2197 "Python/bytecodes.c" + #line 2195 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3126,7 +3126,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2207 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } @@ -3134,7 +3134,7 @@ int err = PyObject_IsTrue(cond); #line 3136 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2213 "Python/bytecodes.c" + #line 2211 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3149,11 +3149,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2223 "Python/bytecodes.c" + #line 2221 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3155 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2225 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" JUMPBY(oparg); } #line 3160 "Python/generated_cases.c.h" @@ -3163,14 +3163,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2230 "Python/bytecodes.c" + #line 2228 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3172 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2235 "Python/bytecodes.c" + #line 2233 "Python/bytecodes.c" } #line 3176 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3178,7 +3178,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2239 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3192,7 +3192,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2248 "Python/bytecodes.c" + #line 2246 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3209,7 +3209,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2256 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3218,7 +3218,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2261 "Python/bytecodes.c" + #line 2259 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3235,7 +3235,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2271 "Python/bytecodes.c" + #line 2269 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3242 "Python/generated_cases.c.h" @@ -3247,7 +3247,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2276 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3254 "Python/generated_cases.c.h" @@ -3260,7 +3260,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2281 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -3273,12 +3273,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2287 "Python/bytecodes.c" + #line 2285 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3280 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2290 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3284 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3288,7 +3288,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2294 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3313,7 +3313,7 @@ } #line 3315 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2317 "Python/bytecodes.c" + #line 2315 "Python/bytecodes.c" } #line 3319 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3325,7 +3325,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2335 "Python/bytecodes.c" + #line 2333 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3365,7 +3365,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2369 "Python/bytecodes.c" + #line 2367 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3398,7 +3398,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2397 "Python/bytecodes.c" + #line 2395 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3429,7 +3429,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2420 "Python/bytecodes.c" + #line 2418 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3460,7 +3460,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2443 "Python/bytecodes.c" + #line 2441 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3488,7 +3488,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2464 "Python/bytecodes.c" + #line 2462 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3511,7 +3511,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2482 "Python/bytecodes.c" + #line 2480 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3536,7 +3536,7 @@ } #line 3538 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2505 "Python/bytecodes.c" + #line 2503 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3554,7 +3554,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2514 "Python/bytecodes.c" + #line 2512 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3582,7 +3582,7 @@ } #line 3584 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2540 "Python/bytecodes.c" + #line 2538 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3601,7 +3601,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2549 "Python/bytecodes.c" + #line 2547 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3631,7 +3631,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2588 "Python/bytecodes.c" + #line 2586 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3655,7 +3655,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2600 "Python/bytecodes.c" + #line 2598 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3686,7 +3686,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2619 "Python/bytecodes.c" + #line 2617 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3710,7 +3710,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2631 "Python/bytecodes.c" + #line 2629 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3733,7 +3733,7 @@ } TARGET(KW_NAMES) { - #line 2647 "Python/bytecodes.c" + #line 2645 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); @@ -3742,7 +3742,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2653 "Python/bytecodes.c" + #line 2651 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3765,7 +3765,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2699 "Python/bytecodes.c" + #line 2697 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3859,7 +3859,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2787 "Python/bytecodes.c" + #line 2785 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3878,7 +3878,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2799 "Python/bytecodes.c" + #line 2797 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3912,7 +3912,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2827 "Python/bytecodes.c" + #line 2825 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3956,7 +3956,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2865 "Python/bytecodes.c" + #line 2863 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3979,7 +3979,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2877 "Python/bytecodes.c" + #line 2875 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4004,7 +4004,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2891 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4028,7 +4028,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2905 "Python/bytecodes.c" + #line 2903 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4083,7 +4083,7 @@ TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2957 "Python/bytecodes.c" + #line 2955 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4101,7 +4101,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2967 "Python/bytecodes.c" + #line 2965 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4137,7 +4137,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2992 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4179,7 +4179,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3023 "Python/bytecodes.c" + #line 3021 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4225,7 +4225,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3058 "Python/bytecodes.c" + #line 3056 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4271,7 +4271,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3093 "Python/bytecodes.c" + #line 3091 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4309,7 +4309,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3120 "Python/bytecodes.c" + #line 3118 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4348,7 +4348,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3150 "Python/bytecodes.c" + #line 3148 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4373,7 +4373,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3170 "Python/bytecodes.c" + #line 3168 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4417,7 +4417,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3204 "Python/bytecodes.c" + #line 3202 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4459,7 +4459,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3236 "Python/bytecodes.c" + #line 3234 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4501,7 +4501,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3268 "Python/bytecodes.c" + #line 3266 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4539,7 +4539,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3299 "Python/bytecodes.c" + #line 3297 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4545 "Python/generated_cases.c.h" } @@ -4550,7 +4550,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3303 "Python/bytecodes.c" + #line 3301 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4616,7 +4616,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3365 "Python/bytecodes.c" + #line 3363 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4623 "Python/generated_cases.c.h" @@ -4630,7 +4630,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3371 "Python/bytecodes.c" + #line 3369 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4650,7 +4650,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3385 "Python/bytecodes.c" + #line 3383 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4682,7 +4682,7 @@ } TARGET(RETURN_GENERATOR) { - #line 3412 "Python/bytecodes.c" + #line 3410 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4711,13 +4711,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3435 "Python/bytecodes.c" + #line 3433 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4717 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3437 "Python/bytecodes.c" + #line 3435 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4723 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4729,7 +4729,7 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3441 "Python/bytecodes.c" + #line 3439 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -4744,7 +4744,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3450 "Python/bytecodes.c" + #line 3448 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4764,7 +4764,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3463 "Python/bytecodes.c" + #line 3461 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -4778,7 +4778,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3470 "Python/bytecodes.c" + #line 3468 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4785 "Python/generated_cases.c.h" @@ -4793,7 +4793,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3475 "Python/bytecodes.c" + #line 3473 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4811,7 +4811,7 @@ #line 4812 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3490 "Python/bytecodes.c" + #line 3488 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4817 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4823,7 +4823,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3495 "Python/bytecodes.c" + #line 3493 "Python/bytecodes.c" assert(oparg >= 2); #line 4829 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4832,7 +4832,7 @@ } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3499 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4848,14 +4848,14 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3513 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); #line 4854 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3517 "Python/bytecodes.c" + #line 3515 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); #line 4861 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); @@ -4863,7 +4863,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3522 "Python/bytecodes.c" + #line 3520 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4877,7 +4877,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3533 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4891,7 +4891,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3544 "Python/bytecodes.c" + #line 3542 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4908,7 +4908,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3558 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4925,7 +4925,7 @@ } TARGET(EXTENDED_ARG) { - #line 3572 "Python/bytecodes.c" + #line 3570 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; @@ -4935,14 +4935,14 @@ } TARGET(CACHE) { - #line 3580 "Python/bytecodes.c" + #line 3578 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); #line 4942 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3585 "Python/bytecodes.c" + #line 3583 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); #line 4949 "Python/generated_cases.c.h" diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 421d9795e7da76..4e31a5e69614bb 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -18,6 +18,21 @@ ((OP) == POP_BLOCK) || \ 0 +#define EXIT_TRACE 300 +#define SET_IP 301 +#define _GUARD_BOTH_INT 302 +#define _BINARY_OP_MULTIPLY_INT 303 +#define _BINARY_OP_ADD_INT 304 +#define _BINARY_OP_SUBTRACT_INT 305 +#define _GUARD_BOTH_FLOAT 306 +#define _BINARY_OP_MULTIPLY_FLOAT 307 +#define _BINARY_OP_ADD_FLOAT 308 +#define _BINARY_OP_SUBTRACT_FLOAT 309 +#define _GUARD_BOTH_UNICODE 310 +#define _BINARY_OP_ADD_UNICODE 311 +#define _LOAD_LOCALS 312 +#define _LOAD_FROM_DICT_OR_GLOBALS 313 + #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #else @@ -885,12 +900,19 @@ struct opcode_metadata { int flags; }; +struct opcode_macro_expansion { + int nuops; + struct { int16_t uop; int8_t size; int8_t offset; } uops[8]; +}; + + #define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) #ifndef NEED_OPCODE_METADATA extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; +extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [NOP] = { true, INSTR_FMT_IX, 0 }, @@ -1101,4 +1123,88 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, }; +const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { + [NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } }, + [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, + [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { LOAD_FAST_AND_CLEAR, 0, 0 } } }, + [LOAD_CONST] = { .nuops = 1, .uops = { { LOAD_CONST, 0, 0 } } }, + [STORE_FAST] = { .nuops = 1, .uops = { { STORE_FAST, 0, 0 } } }, + [POP_TOP] = { .nuops = 1, .uops = { { POP_TOP, 0, 0 } } }, + [PUSH_NULL] = { .nuops = 1, .uops = { { PUSH_NULL, 0, 0 } } }, + [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, + [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, + [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, + [UNARY_INVERT] = { .nuops = 1, .uops = { { UNARY_INVERT, 0, 0 } } }, + [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, + [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, + [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, + [BINARY_SUBSCR_TUPLE_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_TUPLE_INT, 0, 0 } } }, + [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, + [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, + [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, + [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, + [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, + [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, + [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { CALL_INTRINSIC_1, 0, 0 } } }, + [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { CALL_INTRINSIC_2, 0, 0 } } }, + [GET_AITER] = { .nuops = 1, .uops = { { GET_AITER, 0, 0 } } }, + [GET_ANEXT] = { .nuops = 1, .uops = { { GET_ANEXT, 0, 0 } } }, + [GET_AWAITABLE] = { .nuops = 1, .uops = { { GET_AWAITABLE, 0, 0 } } }, + [POP_EXCEPT] = { .nuops = 1, .uops = { { POP_EXCEPT, 0, 0 } } }, + [LOAD_ASSERTION_ERROR] = { .nuops = 1, .uops = { { LOAD_ASSERTION_ERROR, 0, 0 } } }, + [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } }, + [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } }, + [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } }, + [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, + [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, + [UNPACK_EX] = { .nuops = 1, .uops = { { UNPACK_EX, 0, 0 } } }, + [DELETE_ATTR] = { .nuops = 1, .uops = { { DELETE_ATTR, 0, 0 } } }, + [STORE_GLOBAL] = { .nuops = 1, .uops = { { STORE_GLOBAL, 0, 0 } } }, + [DELETE_GLOBAL] = { .nuops = 1, .uops = { { DELETE_GLOBAL, 0, 0 } } }, + [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, + [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, + [LOAD_DEREF] = { .nuops = 1, .uops = { { LOAD_DEREF, 0, 0 } } }, + [STORE_DEREF] = { .nuops = 1, .uops = { { STORE_DEREF, 0, 0 } } }, + [COPY_FREE_VARS] = { .nuops = 1, .uops = { { COPY_FREE_VARS, 0, 0 } } }, + [BUILD_STRING] = { .nuops = 1, .uops = { { BUILD_STRING, 0, 0 } } }, + [BUILD_TUPLE] = { .nuops = 1, .uops = { { BUILD_TUPLE, 0, 0 } } }, + [BUILD_LIST] = { .nuops = 1, .uops = { { BUILD_LIST, 0, 0 } } }, + [LIST_EXTEND] = { .nuops = 1, .uops = { { LIST_EXTEND, 0, 0 } } }, + [SET_UPDATE] = { .nuops = 1, .uops = { { SET_UPDATE, 0, 0 } } }, + [BUILD_SET] = { .nuops = 1, .uops = { { BUILD_SET, 0, 0 } } }, + [BUILD_MAP] = { .nuops = 1, .uops = { { BUILD_MAP, 0, 0 } } }, + [SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { SETUP_ANNOTATIONS, 0, 0 } } }, + [BUILD_CONST_KEY_MAP] = { .nuops = 1, .uops = { { BUILD_CONST_KEY_MAP, 0, 0 } } }, + [DICT_UPDATE] = { .nuops = 1, .uops = { { DICT_UPDATE, 0, 0 } } }, + [DICT_MERGE] = { .nuops = 1, .uops = { { DICT_MERGE, 0, 0 } } }, + [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } }, + [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, + [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, + [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, + [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, + [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } }, + [IS_OP] = { .nuops = 1, .uops = { { IS_OP, 0, 0 } } }, + [CONTAINS_OP] = { .nuops = 1, .uops = { { CONTAINS_OP, 0, 0 } } }, + [CHECK_EG_MATCH] = { .nuops = 1, .uops = { { CHECK_EG_MATCH, 0, 0 } } }, + [CHECK_EXC_MATCH] = { .nuops = 1, .uops = { { CHECK_EXC_MATCH, 0, 0 } } }, + [GET_LEN] = { .nuops = 1, .uops = { { GET_LEN, 0, 0 } } }, + [MATCH_CLASS] = { .nuops = 1, .uops = { { MATCH_CLASS, 0, 0 } } }, + [MATCH_MAPPING] = { .nuops = 1, .uops = { { MATCH_MAPPING, 0, 0 } } }, + [MATCH_SEQUENCE] = { .nuops = 1, .uops = { { MATCH_SEQUENCE, 0, 0 } } }, + [MATCH_KEYS] = { .nuops = 1, .uops = { { MATCH_KEYS, 0, 0 } } }, + [GET_ITER] = { .nuops = 1, .uops = { { GET_ITER, 0, 0 } } }, + [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } }, + [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, + [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, + [EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { EXIT_INIT_CHECK, 0, 0 } } }, + [MAKE_FUNCTION] = { .nuops = 1, .uops = { { MAKE_FUNCTION, 0, 0 } } }, + [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { SET_FUNCTION_ATTRIBUTE, 0, 0 } } }, + [BUILD_SLICE] = { .nuops = 1, .uops = { { BUILD_SLICE, 0, 0 } } }, + [CONVERT_VALUE] = { .nuops = 1, .uops = { { CONVERT_VALUE, 0, 0 } } }, + [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } }, + [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } }, + [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, + [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, +}; #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 95cd7824e32e42..0a6cc5c92f04f5 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -3,7 +3,9 @@ #include "opcode.h" #include "pycore_interp.h" #include "pycore_opcode.h" +#include "opcode_metadata.h" #include "pycore_pystate.h" +#include "pycore_uops.h" #include "cpython/optimizer.h" #include #include @@ -278,3 +280,200 @@ PyUnstable_Optimizer_NewCounter(void) opt->count = 0; return (PyObject *)opt; } + +///////////////////// Experimental UOp Optimizer ///////////////////// + +#ifdef Py_DEBUG + /* For debugging the interpreter: */ +# define LLTRACE 1 /* Low-level trace feature */ +#endif + +static void +uop_dealloc(_PyUOpExecutorObject *self) { + PyObject_Free(self); +} + +static PyTypeObject UOpExecutor_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "uop_executor", + .tp_basicsize = sizeof(_PyUOpExecutorObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_dealloc = (destructor)uop_dealloc, +}; + +static int +translate_bytecode_to_trace( + PyCodeObject *code, + _Py_CODEUNIT *instr, + _PyUOpInstruction *trace, + int max_length) +{ +#ifdef LLTRACE + char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); + int lltrace = 0; + if (uop_debug != NULL && *uop_debug >= '0') { + lltrace = *uop_debug - '0'; // TODO: Parse an int and all that + } + if (lltrace >= 4) { + fprintf(stderr, + "Optimizing %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + } +#define ADD_TO_TRACE(OPCODE, OPERAND) \ + if (lltrace >= 2) { \ + const char *opname = (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : ""; \ + fprintf(stderr, " ADD_TO_TRACE(%s %d, %" PRIu64 ")\n", opname, (OPCODE), (uint64_t)(OPERAND)); \ + } \ + trace[trace_length].opcode = (OPCODE); \ + trace[trace_length].operand = (OPERAND); \ + trace_length++; +#else +#define ADD_TO_TRACE(OPCODE, OPERAND) \ + trace[trace_length].opcode = (OPCODE); \ + trace[trace_length].operand = (OPERAND); \ + trace_length++; +#endif + + int trace_length = 0; + // Always reserve space for one uop, plus SET_UP, plus EXIT_TRACE + while (trace_length + 3 <= max_length) { + int opcode = instr->op.code; + uint64_t operand = instr->op.arg; + switch (opcode) { + case LOAD_FAST_LOAD_FAST: + { + // Reserve space for two uops (+ SETUP + EXIT_TRACE) + if (trace_length + 4 > max_length) { + goto done; + } + uint64_t oparg1 = operand >> 4; + uint64_t oparg2 = operand & 15; + ADD_TO_TRACE(LOAD_FAST, oparg1); + ADD_TO_TRACE(LOAD_FAST, oparg2); + break; + } + default: + { + const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; + if (expansion->nuops > 0) { + // Reserve space for nuops (+ SETUP + EXIT_TRACE) + int nuops = expansion->nuops; + if (trace_length + nuops + 2 > max_length) { + goto done; + } + for (int i = 0; i < nuops; i++) { + int offset = expansion->uops[i].offset; + switch (expansion->uops[i].size) { + case 0: + break; + case 1: + operand = read_u16(&instr[offset].cache); + break; + case 2: + operand = read_u32(&instr[offset].cache); + break; + case 4: + operand = read_u64(&instr[offset].cache); + break; + default: + fprintf(stderr, + "opcode=%d, operand=%" PRIu64 "; nuops=%d, i=%d; size=%d, offset=%d\n", + opcode, operand, nuops, i, + expansion->uops[i].size, + expansion->uops[i].offset); + Py_FatalError("garbled expansion"); + } + ADD_TO_TRACE(expansion->uops[i].uop, operand); + assert(expansion->uops[0].size == 0); // TODO + } + break; + } + // fprintf(stderr, "Unsupported opcode %d\n", opcode); + goto done; // Break out of while loop + } + } + instr++; + // Add cache size for opcode + instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; + ADD_TO_TRACE(SET_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + } +done: + if (trace_length > 0) { + ADD_TO_TRACE(EXIT_TRACE, 0); +#ifdef LLTRACE + if (lltrace >= 1) { + fprintf(stderr, + "Created a trace for %s (%s:%d) at offset %ld -- length %d\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive), + trace_length); + } +#endif + } + else { +#ifdef LLTRACE + if (lltrace >= 4) { + fprintf(stderr, + "No trace for %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + } +#endif + } + return trace_length; + +#undef ADD_TO_TRACE +} + +static int +uop_optimize( + _PyOptimizerObject *self, + PyCodeObject *code, + _Py_CODEUNIT *instr, + _PyExecutorObject **exec_ptr) +{ + _PyUOpInstruction trace[_Py_UOP_MAX_TRACE_LENGTH]; + int trace_length = translate_bytecode_to_trace(code, instr, trace, _Py_UOP_MAX_TRACE_LENGTH); + if (trace_length <= 0) { + // Error or nothing translated + return trace_length; + } + OBJECT_STAT_INC(optimization_traces_created); + _PyUOpExecutorObject *executor = (_PyUOpExecutorObject *)_PyObject_New(&UOpExecutor_Type); + if (executor == NULL) { + return -1; + } + executor->base.execute = _PyUopExecute; + memcpy(executor->trace, trace, trace_length * sizeof(_PyUOpInstruction)); + *exec_ptr = (_PyExecutorObject *)executor; + return 1; +} + +static PyTypeObject UOpOptimizer_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "uop_optimizer", + .tp_basicsize = sizeof(_PyOptimizerObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, +}; + +PyObject * +PyUnstable_Optimizer_NewUOpOptimizer(void) +{ + _PyOptimizerObject *opt = (_PyOptimizerObject *)_PyObject_New(&UOpOptimizer_Type); + if (opt == NULL) { + return NULL; + } + opt->optimize = uop_optimize; + opt->resume_threshold = UINT16_MAX; + opt->backedge_threshold = 0; + return (PyObject *)opt; +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5a5b14fbb03144..6117f3a19a5509 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1181,6 +1181,19 @@ init_interp_main(PyThreadState *tstate) #endif } + // Turn on experimental tier 2 (uops-based) optimizer + if (is_main_interp) { + char *envvar = Py_GETENV("PYTHONUOPS"); + int enabled = envvar != NULL && *envvar > '0'; + if (_Py_get_xoption(&config->xoptions, L"uops") != NULL) { + enabled = 1; + } + if (enabled) { + PyObject *opt = PyUnstable_Optimizer_NewUOpOptimizer(); + PyUnstable_SetOptimizer((_PyOptimizerObject *)opt); + } + } + assert(!_PyErr_Occurred(tstate)); return _PyStatus_OK(); diff --git a/Python/specialize.c b/Python/specialize.c index 0006aa733bd6cb..3f51432a63af1f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -195,6 +195,10 @@ print_object_stats(FILE *out, ObjectStats *stats) fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits); fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses); + fprintf(out, "Optimization attempts: %" PRIu64 "\n", stats->optimization_attempts); + fprintf(out, "Optimization traces created: %" PRIu64 "\n", stats->optimization_traces_created); + fprintf(out, "Optimization traces executed: %" PRIu64 "\n", stats->optimization_traces_executed); + fprintf(out, "Optimization uops executed: %" PRIu64 "\n", stats->optimization_uops_executed); } static void diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 51b79c25f9e20b..9bc7285e18b2fb 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -83,6 +83,7 @@ def clean_lines(text): Python/deepfreeze/*.c Python/frozen_modules/*.h Python/generated_cases.c.h +Python/executor_cases.c.h # not actually source Python/bytecodes.c diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 9cce3f3b25c18d..73eec6631d9512 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -366,6 +366,8 @@ Python/sysmodule.c - whatstrings - Python/optimizer.c - DefaultOptimizer_Type - Python/optimizer.c - CounterExecutor_Type - Python/optimizer.c - CounterOptimizer_Type - +Python/optimizer.c - UOpExecutor_Type - +Python/optimizer.c - UOpOptimizer_Type - Python/optimizer.c - _PyOptimizer_Default - ##----------------------- diff --git a/Tools/cases_generator/README.md b/Tools/cases_generator/README.md index c595a932ac4470..fc9331656fe787 100644 --- a/Tools/cases_generator/README.md +++ b/Tools/cases_generator/README.md @@ -9,7 +9,7 @@ What's currently here: - `plexer.py`: OO interface on top of lexer.py; main class: `PLexer` - `parser.py`: Parser for instruction definition DSL; main class `Parser` - `generate_cases.py`: driver script to read `Python/bytecodes.c` and - write `Python/generated_cases.c.h` + write `Python/generated_cases.c.h` (and several other files) - `test_generator.py`: tests, require manual running using `pytest` Note that there is some dummy C code at the top and bottom of diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1afdeef41f0efc..afeb31dd441ae6 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -29,6 +29,9 @@ DEFAULT_PYMETADATA_OUTPUT = os.path.relpath( os.path.join(ROOT, "Lib/_opcode_metadata.py") ) +DEFAULT_EXECUTOR_OUTPUT = os.path.relpath( + os.path.join(ROOT, "Python/executor_cases.c.h") +) BEGIN_MARKER = "// BEGIN BYTECODES //" END_MARKER = "// END BYTECODES //" RE_PREDICTED = ( @@ -61,6 +64,13 @@ arg_parser.add_argument( "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" ) +arg_parser.add_argument( + "-e", + "--executor-cases", + type=str, + help="Write executor cases to this file", + default=DEFAULT_EXECUTOR_OUTPUT, +) def effect_size(effect: StackEffect) -> tuple[int, str]: @@ -176,14 +186,14 @@ def indent(self): self.prefix = self.prefix[:-4] @contextlib.contextmanager - def block(self, head: str): + def block(self, head: str, tail: str = ""): if head: self.emit(head + " {") else: self.emit("{") with self.indent(): yield - self.emit("}") + self.emit("}" + tail) def stack_adjust( self, @@ -290,6 +300,29 @@ def emit_macros(cls, out: Formatter): f"(_PyOpcode_opcode_metadata[(OP)].flags & ({name}))") +FORBIDDEN_NAMES_IN_UOPS = ( + "resume_with_error", # Proxy for "goto", which isn't an IDENTIFIER + "unbound_local_error", + "kwnames", + "next_instr", + "oparg1", # Proxy for super-instructions like LOAD_FAST_LOAD_FAST + "JUMPBY", + "DISPATCH", + "INSTRUMENTED_JUMP", + "throwflag", + "exception_unwind", + "import_from", + "import_name", + "_PyObject_CallNoArgs", # Proxy for BEFORE_WITH +) + + +# Interpreter tiers +TIER_ONE = 1 # Specializing adaptive interpreter (PEP 659) +TIER_TWO = 2 # Experimental tracing interpreter +Tiers: typing.TypeAlias = typing.Literal[1, 2] + + @dataclasses.dataclass class Instruction: """An instruction with additional data and code.""" @@ -353,7 +386,32 @@ def __init__(self, inst: parser.InstDef): cache = "0" self.instr_fmt = fmt - def write(self, out: Formatter) -> None: + def is_viable_uop(self) -> bool: + """Whether this instruction is viable as a uop.""" + if self.always_exits: + return False + if self.instr_flags.HAS_ARG_FLAG: + # If the instruction uses oparg, it cannot use any caches + for c in self.cache_effects: + if c.name != UNUSED: + return False + else: + # If it doesn't use oparg, it can have one cache entry + caches: list[parser.CacheEffect] = [] + cache_offset = 0 + for c in self.cache_effects: + if c.name != UNUSED: + caches.append(c) + cache_offset += c.size + if len(caches) > 1: + return False + for forbidden in FORBIDDEN_NAMES_IN_UOPS: + # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions + if variable_used(self.inst, forbidden): + return False + return True + + def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct if family := self.family: @@ -400,7 +458,7 @@ def write(self, out: Formatter) -> None: # out.emit(f"next_instr += OPSIZE({self.inst.name}) - 1;") - self.write_body(out, 0) + self.write_body(out, 0, tier=tier) # Skip the rest if the block always exits if self.always_exits: @@ -427,10 +485,16 @@ def write(self, out: Formatter) -> None: out.assign(dst, oeffect) # Write cache effect - if self.cache_offset: + if tier == TIER_ONE and self.cache_offset: out.emit(f"next_instr += {self.cache_offset};") - def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None: + def write_body( + self, + out: Formatter, + dedent: int, + cache_adjust: int = 0, + tier: Tiers = TIER_ONE, + ) -> None: """Write the instruction body.""" # Write cache effect variable declarations and initializations cache_offset = cache_adjust @@ -447,9 +511,12 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None else: typ = f"uint{bits}_t " func = f"read_u{bits}" - out.emit( - f"{typ}{ceffect.name} = {func}(&next_instr[{cache_offset}].cache);" - ) + if tier == TIER_ONE: + out.emit( + f"{typ}{ceffect.name} = {func}(&next_instr[{cache_offset}].cache);" + ) + else: + out.emit(f"{typ}{ceffect.name} = operand;") cache_offset += ceffect.size assert cache_offset == self.cache_offset + cache_adjust @@ -573,16 +640,24 @@ class Analyzer: output_filename: str metadata_filename: str pymetadata_filename: str + executor_filename: str errors: int = 0 emit_line_directives: bool = False - def __init__(self, input_filenames: list[str], output_filename: str, - metadata_filename: str, pymetadata_filename: str): + def __init__( + self, + input_filenames: list[str], + output_filename: str, + metadata_filename: str, + pymetadata_filename: str, + executor_filename: str, + ): """Read the input file.""" self.input_filenames = input_filenames self.output_filename = output_filename self.metadata_filename = metadata_filename self.pymetadata_filename = pymetadata_filename + self.executor_filename = executor_filename def error(self, msg: str, node: parser.Node) -> None: lineno = 0 @@ -1107,6 +1182,8 @@ def write_metadata(self) -> None: self.write_pseudo_instrs() + self.write_uop_defines() + self.write_stack_effect_functions() # Write type definitions @@ -1114,12 +1191,17 @@ def write_metadata(self) -> None: InstructionFlags.emit_macros(self.out) - self.out.emit("struct opcode_metadata {") - with self.out.indent(): + with self.out.block("struct opcode_metadata", ";"): self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") self.out.emit("int flags;") - self.out.emit("};") + self.out.emit("") + + with self.out.block("struct opcode_macro_expansion", ";"): + self.out.emit("int nuops;") + self.out.emit("struct { int16_t uop; int8_t size; int8_t offset; } uops[8];") + self.out.emit("") + self.out.emit("") self.out.emit("#define OPCODE_METADATA_FMT(OP) " "(_PyOpcode_opcode_metadata[(OP)].instr_format)") @@ -1130,7 +1212,9 @@ def write_metadata(self) -> None: # Write metadata array declaration self.out.emit("#ifndef NEED_OPCODE_METADATA") self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") + self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") self.out.emit("#else") + self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") # Write metadata for each instruction @@ -1150,6 +1234,31 @@ def write_metadata(self) -> None: # Write end of array self.out.emit("};") + + with self.out.block( + "const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] =", + ";", + ): + # Write macro expansion for each non-pseudo instruction + for thing in self.everything: + match thing: + case OverriddenInstructionPlaceHolder(): + pass + case parser.InstDef(name=name): + instr = self.instrs[name] + if instr.kind != "op" and instr.is_viable_uop(): + self.out.emit( + f"[{name}] = " + f"{{ .nuops = 1, .uops = {{ {{ {name}, 0, 0 }} }} }}," + ) + case parser.Macro(): + # TODO: emit expansion if all parts are viable uops + pass + case parser.Pseudo(): + pass + case _: + typing.assert_never(thing) + self.out.emit("#endif") with open(self.pymetadata_filename, "w") as f: @@ -1184,7 +1293,6 @@ def write_metadata(self) -> None: "opcode for family in _specializations.values() for opcode in family" "]") - def write_pseudo_instrs(self) -> None: """Write the IS_PSEUDO_INSTR macro""" self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) \\") @@ -1192,6 +1300,20 @@ def write_pseudo_instrs(self) -> None: self.out.emit(f" ((OP) == {op}) || \\") self.out.emit(f" 0") + def write_uop_defines(self) -> None: + """Write '#define XXX NNN' for each uop""" + self.out.emit("") + counter = 300 + def add(name: str) -> None: + nonlocal counter + self.out.emit(f"#define {name} {counter}") + counter += 1 + add("EXIT_TRACE") + add("SET_IP") + for instr in self.instrs.values(): + if instr.kind == "op" and instr.is_viable_uop(): + add(instr.name) + def emit_metadata_entry( self, name: str, fmt: str, flags: InstructionFlags ) -> None: @@ -1221,10 +1343,7 @@ def write_instructions(self) -> None: # Create formatter self.out = Formatter(f, 8, self.emit_line_directives) - # Write provenance header - self.out.write_raw(f"{self.out.comment} This file is generated by {THIS}\n") - self.out.write_raw(self.from_source_files()) - self.out.write_raw(f"{self.out.comment} Do not edit!\n") + self.write_provenance_header() # Write and count instructions of all kinds n_instrs = 0 @@ -1252,6 +1371,33 @@ def write_instructions(self) -> None: file=sys.stderr, ) + def write_executor_instructions(self) -> None: + """Generate cases for the Tier 2 interpreter.""" + with open(self.executor_filename, "w") as f: + self.out = Formatter(f, 8) + self.write_provenance_header() + for thing in self.everything: + match thing: + case OverriddenInstructionPlaceHolder(): + self.write_overridden_instr_place_holder(thing) + case parser.InstDef(): + instr = self.instrs[thing.name] + if instr.is_viable_uop(): + self.out.emit("") + with self.out.block(f"case {thing.name}:"): + instr.write(self.out, tier=TIER_TWO) + self.out.emit("break;") + case parser.Macro(): + pass # TODO + case parser.Pseudo(): + pass + case _: + typing.assert_never(thing) + print( + f"Wrote some stuff to {self.executor_filename}", + file=sys.stderr, + ) + def write_overridden_instr_place_holder(self, place_holder: OverriddenInstructionPlaceHolder) -> None: self.out.emit("") @@ -1405,7 +1551,7 @@ def main(): args.input.append(DEFAULT_INPUT) # Raises OSError if input unreadable - a = Analyzer(args.input, args.output, args.metadata, args.pymetadata) + a = Analyzer(args.input, args.output, args.metadata, args.pymetadata, args.executor_cases) if args.emit_line_directives: a.emit_line_directives = True @@ -1415,6 +1561,7 @@ def main(): sys.exit(f"Found {a.errors} errors") a.write_instructions() # Raises OSError if output can't be written a.write_metadata() + a.write_executor_instructions() if __name__ == "__main__": diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index 9ff4c971fd21ac..e374ac41e6a94d 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -44,7 +44,15 @@ def run_cases_test(input: str, expected: str): temp_input.flush() temp_output = tempfile.NamedTemporaryFile("w+") temp_metadata = tempfile.NamedTemporaryFile("w+") - a = generate_cases.Analyzer([temp_input.name], temp_output.name, temp_metadata.name) + temp_pymetadata = tempfile.NamedTemporaryFile("w+") + temp_executor = tempfile.NamedTemporaryFile("w+") + a = generate_cases.Analyzer( + [temp_input.name], + temp_output.name, + temp_metadata.name, + temp_pymetadata.name, + temp_executor.name, + ) a.parse() a.analyze() if a.errors: From 0345b0c2bbf251a0f475cf53e0fb04c79a220e52 Mon Sep 17 00:00:00 2001 From: Skip Montanaro Date: Mon, 26 Jun 2023 22:40:34 -0500 Subject: [PATCH 152/446] gh-106123: Modules/_sha3 appears to no longer be necessary (#106124) --- configure | 1 - configure.ac | 1 - 2 files changed, 2 deletions(-) diff --git a/configure b/configure index e33bf77779e6e2..e6fb5e3c2b0c2f 100755 --- a/configure +++ b/configure @@ -26701,7 +26701,6 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ - Modules/_sha3 \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ diff --git a/configure.ac b/configure.ac index 8f097c41677598..a1ee78047692fd 100644 --- a/configure.ac +++ b/configure.ac @@ -6643,7 +6643,6 @@ SRCDIRS="\ Modules/_hacl \ Modules/_io \ Modules/_multiprocessing \ - Modules/_sha3 \ Modules/_sqlite \ Modules/_sre \ Modules/_testcapi \ From a8210b6df1ed2793c484b3380182ba56c4254a4e Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 26 Jun 2023 23:12:22 -0500 Subject: [PATCH 153/446] GH-105774: Clarify operation of normalize() (GH-106093) --- Doc/library/decimal.rst | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 20c5c7daac73bb..c2b96954c5f8ef 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -743,12 +743,23 @@ Decimal objects .. method:: normalize(context=None) - Normalize the number by stripping the rightmost trailing zeros and - converting any result equal to ``Decimal('0')`` to - ``Decimal('0e0')``. Used for producing canonical values for attributes - of an equivalence class. For example, ``Decimal('32.100')`` and - ``Decimal('0.321000e+2')`` both normalize to the equivalent value - ``Decimal('32.1')``. + Used for producing canonical values of an equivalence + class within either the current context or the specified context. + + This has the same semantics as the unary plus operation, except that if + the final result is finite it is reduced to its simplest form, with all + trailing zeros removed and its sign preserved. That is, while the + coefficient is non-zero and a multiple of ten the coefficient is divided + by ten and the exponent is incremented by 1. Otherwise (the coefficient is + zero) the exponent is set to 0. In all cases the sign is unchanged. + + For example, ``Decimal('32.100')`` and ``Decimal('0.321000e+2')`` both + normalize to the equivalent value ``Decimal('32.1')``. + + Note that rounding is applied *before* reducing to simplest form. + + In the latest versions of the specification, this operation is also known + as ``reduce``. .. method:: number_class(context=None) @@ -2078,6 +2089,26 @@ representative: >>> [v.normalize() for v in values] [Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')] +Q. When does rounding occur in a computation? + +A. It occurs *after* the computation. The philosophy of the decimal +specification is that numbers are considered exact and are created +independent of the current context. They can even have greater +precision than current context. Computations process with those +exact inputs and then rounding (or other context operations) is +applied to the *result* of the computation:: + + >>> getcontext().prec = 5 + >>> pi = Decimal('3.1415926535') # More than 5 digits + >>> pi # All digits are retained + Decimal('3.1415926535') + >>> pi + 0 # Rounded after an addition + Decimal('3.1416') + >>> pi - Decimal('0.00005') # Subtract unrounded numbers, then round + Decimal('3.1415') + >>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded + Decimal('3.1416') + Q. Some decimal values always print with exponential notation. Is there a way to get a non-exponential representation? From 33608fd67df8b1033519f808441ee00289e2dac0 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 27 Jun 2023 16:43:49 +0300 Subject: [PATCH 154/446] gh-92788: Add docs for `ast.Module`, `ast.Expression`, and others (#101055) --- Doc/library/ast.rst | 101 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index f3b0bf0c4f7779..530cf30643687f 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -146,6 +146,102 @@ Node classes Snakes `__ project and all its contributors. + +.. _ast-root-nodes: + +Root nodes +^^^^^^^^^^ + +.. class:: Module(body, type_ignores) + + A Python module, as with :ref:`file input `. + Node type generated by :func:`ast.parse` in the default ``"exec"`` *mode*. + + *body* is a :class:`list` of the module's :ref:`ast-statements`. + + *type_ignores* is a :class:`list` of the module's type ignore comments; + see :func:`ast.parse` for more details. + + .. doctest:: + + >>> print(ast.dump(ast.parse('x = 1'), indent=4)) + Module( + body=[ + Assign( + targets=[ + Name(id='x', ctx=Store())], + value=Constant(value=1))], + type_ignores=[]) + + +.. class:: Expression(body) + + A single Python :ref:`expression input `. + Node type generated by :func:`ast.parse` when *mode* is ``"eval"``. + + *body* is a single node, + one of the :ref:`expression types `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('123', mode='eval'), indent=4)) + Expression( + body=Constant(value=123)) + + +.. class:: Interactive(body) + + A single :ref:`interactive input `, like in :ref:`tut-interac`. + Node type generated by :func:`ast.parse` when *mode* is ``"single"``. + + *body* is a :class:`list` of :ref:`statement nodes `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('x = 1; y = 2', mode='single'), indent=4)) + Interactive( + body=[ + Assign( + targets=[ + Name(id='x', ctx=Store())], + value=Constant(value=1)), + Assign( + targets=[ + Name(id='y', ctx=Store())], + value=Constant(value=2))]) + + +.. class:: FunctionType(argtypes, returns) + + A representation of an old-style type comments for functions, + as Python versions prior to 3.5 didn't support :pep:`484` annotations. + Node type generated by :func:`ast.parse` when *mode* is ``"func_type"``. + + Such type comments would look like this:: + + def sum_two_number(a, b): + # type: (int, int) -> int + return a + b + + *argtypes* is a :class:`list` of :ref:`expression nodes `. + + *returns* is a single :ref:`expression node `. + + .. doctest:: + + >>> print(ast.dump(ast.parse('(int, str) -> List[int]', mode='func_type'), indent=4)) + FunctionType( + argtypes=[ + Name(id='int', ctx=Load()), + Name(id='str', ctx=Load())], + returns=Subscript( + value=Name(id='List', ctx=Load()), + slice=Name(id='int', ctx=Load()), + ctx=Load())) + + .. versionadded:: 3.8 + + Literals ^^^^^^^^ @@ -344,6 +440,8 @@ Variables type_ignores=[]) +.. _ast-expressions: + Expressions ^^^^^^^^^^^ @@ -735,6 +833,9 @@ Comprehensions ifs=[], is_async=1)])) + +.. _ast-statements: + Statements ^^^^^^^^^^ From 0762775a15d1fb238751744872bc99c853bef6c8 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Jun 2023 06:56:39 -0700 Subject: [PATCH 155/446] gh-104584: Add #line directives to executor_cases.c.h (#106126) --- Python/executor_cases.c.h | 254 ++++++++++++++++++++++++ Tools/cases_generator/generate_cases.py | 2 +- 2 files changed, 255 insertions(+), 1 deletion(-) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1bdee40d4f8eec..739cb8499c0079 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9,9 +9,11 @@ case LOAD_FAST: { PyObject *value; + #line 192 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 17 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -19,9 +21,11 @@ case LOAD_FAST_AND_CLEAR: { PyObject *value; + #line 198 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; + #line 29 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -29,8 +33,10 @@ case LOAD_CONST: { PyObject *value; + #line 213 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); + #line 40 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -38,13 +44,17 @@ case STORE_FAST: { PyObject *value = stack_pointer[-1]; + #line 218 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 50 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case POP_TOP: { PyObject *value = stack_pointer[-1]; + #line 241 "Python/bytecodes.c" + #line 58 "Python/executor_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); break; @@ -52,7 +62,9 @@ case PUSH_NULL: { PyObject *res; + #line 245 "Python/bytecodes.c" res = NULL; + #line 68 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -61,7 +73,9 @@ case END_SEND: { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; + #line 264 "Python/bytecodes.c" Py_DECREF(receiver); + #line 79 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; break; @@ -70,9 +84,13 @@ case UNARY_NEGATIVE: { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 279 "Python/bytecodes.c" res = PyNumber_Negative(value); + #line 90 "Python/executor_cases.c.h" Py_DECREF(value); + #line 281 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 94 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -80,8 +98,11 @@ case UNARY_NOT: { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 285 "Python/bytecodes.c" int err = PyObject_IsTrue(value); + #line 104 "Python/executor_cases.c.h" Py_DECREF(value); + #line 287 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -89,6 +110,7 @@ else { res = Py_False; } + #line 114 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -96,9 +118,13 @@ case UNARY_INVERT: { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 297 "Python/bytecodes.c" res = PyNumber_Invert(value); + #line 124 "Python/executor_cases.c.h" Py_DECREF(value); + #line 299 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 128 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -106,8 +132,10 @@ case _GUARD_BOTH_INT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 315 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + #line 139 "Python/executor_cases.c.h" break; } @@ -115,11 +143,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 320 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; + #line 153 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -129,11 +159,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 328 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; + #line 169 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -143,11 +175,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 336 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; + #line 185 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -156,8 +190,10 @@ case _GUARD_BOTH_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 351 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + #line 197 "Python/executor_cases.c.h" break; } @@ -165,11 +201,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 356 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + #line 211 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -179,11 +217,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 364 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + #line 227 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -193,11 +233,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 372 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + #line 243 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -206,8 +248,10 @@ case _GUARD_BOTH_UNICODE: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); + #line 255 "Python/executor_cases.c.h" break; } @@ -215,11 +259,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 392 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; + #line 269 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -230,6 +276,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; + #line 462 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -242,6 +289,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; + #line 293 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -252,6 +300,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; + #line 477 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -264,6 +313,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; + #line 317 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -272,6 +322,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; + #line 492 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -285,6 +336,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 340 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -294,6 +346,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; + #line 508 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -307,6 +360,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); + #line 364 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -316,6 +370,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; + #line 524 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -323,11 +378,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } + #line 382 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); + #line 532 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub + #line 389 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -338,7 +396,9 @@ case LIST_APPEND: { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 564 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; + #line 402 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -346,9 +406,13 @@ case SET_ADD: { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 568 "Python/bytecodes.c" int err = PySet_Add(set, v); + #line 412 "Python/executor_cases.c.h" Py_DECREF(v); + #line 570 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 416 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -357,6 +421,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 599 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -373,6 +438,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 442 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -381,11 +447,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 618 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; + #line 457 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -393,11 +461,15 @@ case DELETE_SUBSCR: { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; + #line 626 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); + #line 468 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); + #line 629 "Python/bytecodes.c" if (err) goto pop_2_error; + #line 473 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -405,10 +477,14 @@ case CALL_INTRINSIC_1: { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 633 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); + #line 484 "Python/executor_cases.c.h" Py_DECREF(value); + #line 636 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 488 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -417,11 +493,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; + #line 640 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); + #line 500 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); + #line 643 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 505 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -430,6 +510,7 @@ case GET_AITER: { PyObject *obj = stack_pointer[-1]; PyObject *iter; + #line 748 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -442,12 +523,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); + #line 527 "Python/executor_cases.c.h" Py_DECREF(obj); + #line 761 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); + #line 534 "Python/executor_cases.c.h" Py_DECREF(obj); + #line 766 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -460,6 +545,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } + #line 549 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -467,6 +553,7 @@ case GET_ANEXT: { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; + #line 781 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -509,6 +596,7 @@ Py_DECREF(next_iter); } } + #line 600 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -517,13 +605,16 @@ case GET_AWAITABLE: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 826 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } + #line 616 "Python/executor_cases.c.h" Py_DECREF(iterable); + #line 833 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -540,21 +631,26 @@ } if (iter == NULL) goto pop_1_error; + #line 635 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } case POP_EXCEPT: { PyObject *exc_value = stack_pointer[-1]; + #line 963 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); + #line 645 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case LOAD_ASSERTION_ERROR: { PyObject *value; + #line 1014 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); + #line 654 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -562,6 +658,7 @@ case LOAD_BUILD_CLASS: { PyObject *bc; + #line 1018 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -583,6 +680,7 @@ if (true) goto error; } } + #line 684 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -590,26 +688,33 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; + #line 1043 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); + #line 699 "Python/executor_cases.c.h" Py_DECREF(v); + #line 1050 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); + #line 708 "Python/executor_cases.c.h" Py_DECREF(v); + #line 1057 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 712 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_NAME: { + #line 1061 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -626,18 +731,21 @@ name); goto error; } + #line 735 "Python/executor_cases.c.h" break; } case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 1104 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); + #line 749 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -647,6 +755,7 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 1114 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -654,6 +763,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 767 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -663,6 +773,7 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 1125 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -670,6 +781,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 785 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -678,36 +790,49 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; + #line 1136 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); + #line 798 "Python/executor_cases.c.h" Py_DECREF(seq); + #line 1140 "Python/bytecodes.c" if (res == 0) goto pop_1_error; + #line 802 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; + #line 1171 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + #line 812 "Python/executor_cases.c.h" Py_DECREF(owner); + #line 1174 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 816 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; + #line 1178 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); + #line 826 "Python/executor_cases.c.h" Py_DECREF(v); + #line 1181 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 830 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_GLOBAL: { + #line 1185 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -719,11 +844,13 @@ } goto error; } + #line 848 "Python/executor_cases.c.h" break; } case _LOAD_LOCALS: { PyObject *locals; + #line 1199 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -731,6 +858,7 @@ if (true) goto error; } Py_INCREF(locals); + #line 862 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -739,6 +867,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; + #line 1211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -795,11 +924,13 @@ } } } + #line 928 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } case DELETE_DEREF: { + #line 1381 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -810,12 +941,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); + #line 945 "Python/executor_cases.c.h" break; } case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; + #line 1394 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -850,12 +983,14 @@ } Py_INCREF(value); } + #line 987 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } case LOAD_DEREF: { PyObject *value; + #line 1431 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -863,6 +998,7 @@ if (true) goto error; } Py_INCREF(value); + #line 1002 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -870,15 +1006,18 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; + #line 1441 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); + #line 1015 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case COPY_FREE_VARS: { + #line 1448 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -889,17 +1028,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } + #line 1032 "Python/executor_cases.c.h" break; } case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; + #line 1461 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); + #line 1041 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } + #line 1463 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1047 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -909,8 +1053,10 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; + #line 1467 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1060 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -920,8 +1066,10 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; + #line 1472 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1073 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -931,6 +1079,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 1477 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -941,10 +1090,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } + #line 1094 "Python/executor_cases.c.h" Py_DECREF(iterable); + #line 1488 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); + #line 1100 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -953,9 +1105,13 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 1495 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); + #line 1111 "Python/executor_cases.c.h" Py_DECREF(iterable); + #line 1497 "Python/bytecodes.c" if (err < 0) goto pop_1_error; + #line 1115 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -963,6 +1119,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; + #line 1501 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -977,6 +1134,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } + #line 1138 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -986,6 +1144,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; + #line 1518 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -993,10 +1152,13 @@ if (map == NULL) goto error; + #line 1156 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } + #line 1526 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } + #line 1162 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1004,6 +1166,7 @@ } case SETUP_ANNOTATIONS: { + #line 1530 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1043,6 +1206,7 @@ Py_DECREF(ann_dict); } } + #line 1210 "Python/executor_cases.c.h" break; } @@ -1050,6 +1214,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; + #line 1572 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1059,11 +1224,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); + #line 1228 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); + #line 1582 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } + #line 1235 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1071,6 +1239,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; + #line 1586 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1078,9 +1247,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } + #line 1251 "Python/executor_cases.c.h" Py_DECREF(update); + #line 1594 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 1256 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1088,13 +1260,17 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; + #line 1600 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); + #line 1269 "Python/executor_cases.c.h" Py_DECREF(update); + #line 1605 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 1274 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1103,11 +1279,13 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; + #line 1611 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; + #line 1289 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1118,16 +1296,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; + #line 1694 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + #line 1307 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); + #line 1701 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; + #line 1313 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1141,6 +1323,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; + #line 1705 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1163,6 +1346,7 @@ res = res2; res2 = NULL; } + #line 1350 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1173,6 +1357,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 2037 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1183,6 +1368,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; + #line 1372 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1192,6 +1378,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 2051 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1206,6 +1393,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; + #line 1397 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1215,6 +1403,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 2069 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1226,6 +1415,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + #line 1419 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1235,10 +1425,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 2083 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; + #line 1431 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 2085 "Python/bytecodes.c" b = res ? Py_True : Py_False; + #line 1436 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1248,11 +1442,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 2089 "Python/bytecodes.c" int res = PySequence_Contains(right, left); + #line 1448 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 2091 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; + #line 1454 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1263,9 +1461,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; + #line 2096 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { + #line 1467 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 2098 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1273,8 +1474,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); + #line 1478 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 2106 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1283,6 +1486,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } + #line 1490 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1292,15 +1496,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 2117 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { + #line 1503 "Python/executor_cases.c.h" Py_DECREF(right); + #line 2120 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); + #line 1510 "Python/executor_cases.c.h" Py_DECREF(right); + #line 2125 "Python/bytecodes.c" b = res ? Py_True : Py_False; + #line 1514 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1308,11 +1518,13 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; + #line 2246 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; + #line 1528 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1323,13 +1535,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; + #line 2254 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); + #line 1544 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); + #line 2259 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1337,6 +1552,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } + #line 1556 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1345,8 +1561,10 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2269 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; + #line 1568 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1355,8 +1573,10 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2274 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; + #line 1580 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1366,9 +1586,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; + #line 2279 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; + #line 1594 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1377,10 +1599,14 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2285 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); + #line 1606 "Python/executor_cases.c.h" Py_DECREF(iterable); + #line 2288 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; + #line 1610 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1388,6 +1614,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2292 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1410,8 +1637,11 @@ if (iter == NULL) { goto error; } + #line 1641 "Python/executor_cases.c.h" Py_DECREF(iterable); + #line 2315 "Python/bytecodes.c" } + #line 1645 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1421,6 +1651,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; + #line 2547 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -1441,6 +1672,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; + #line 1676 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1449,6 +1681,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; + #line 2586 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -1458,6 +1691,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); + #line 1695 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -1466,6 +1700,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; + #line 2955 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1473,6 +1708,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } + #line 1712 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1480,6 +1716,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; + #line 3369 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1491,6 +1728,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; + #line 1732 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -1498,6 +1736,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; + #line 3383 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1522,6 +1761,7 @@ default: Py_UNREACHABLE(); } + #line 1765 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -1532,11 +1772,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; + #line 3433 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); + #line 1778 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); + #line 3435 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } + #line 1784 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -1546,12 +1790,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; + #line 3439 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; + #line 1801 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -1559,6 +1805,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 3448 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1569,6 +1816,7 @@ else { res = value; } + #line 1820 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -1577,10 +1825,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; + #line 3461 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; + #line 1834 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1589,8 +1839,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; + #line 3468 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); + #line 1846 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -1599,7 +1851,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; + #line 3493 "Python/bytecodes.c" assert(oparg >= 2); + #line 1857 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index afeb31dd441ae6..d66b28139e43fb 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1374,7 +1374,7 @@ def write_instructions(self) -> None: def write_executor_instructions(self) -> None: """Generate cases for the Tier 2 interpreter.""" with open(self.executor_filename, "w") as f: - self.out = Formatter(f, 8) + self.out = Formatter(f, 8, self.emit_line_directives) self.write_provenance_header() for thing in self.everything: match thing: From bb578a0c304dffe43bb28b36b2b1c9153c78b659 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Jun 2023 07:02:51 -0700 Subject: [PATCH 156/446] gh-104584: Fix assert in DEOPT macro -- should fix buildbot (#106131) --- Python/ceval_macros.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 0d41ef5a14cef4..f5c78fc65e1745 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -264,11 +264,12 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define UPDATE_MISS_STATS(INSTNAME) ((void)0) #endif +// NOTE: in the uops version, opcode may be > 255 #define DEOPT_IF(COND, INSTNAME) \ if ((COND)) { \ /* This is only a single jump on release builds! */ \ UPDATE_MISS_STATS((INSTNAME)); \ - assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ + assert(opcode >= 256 || _PyOpcode_Deopt[opcode] == (INSTNAME)); \ GO_TO_INSTRUCTION(INSTNAME); \ } From 2d5a1c281161d037148ffb5983decc6d31c2557d Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 27 Jun 2023 16:26:53 +0100 Subject: [PATCH 157/446] gh-106140: Reorder some fields to facilitate out-of-process inspection (#106143) Signed-off-by: Pablo Galindo --- Include/internal/pycore_interp.h | 71 +++++++++++++++++-------------- Include/internal/pycore_runtime.h | 22 ++++++---- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index a4177f379acc68..8d0bb7672690a8 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -48,12 +48,22 @@ struct _Py_long_state { */ struct _is { - struct _ceval_state ceval; PyInterpreterState *next; + int64_t id; + int64_t id_refcount; + int requires_idref; + PyThread_type_lock id_mutex; + + /* Has been initialized to a safe state. + + In order to be effective, this must be set to 0 during or right + after allocation. */ + int _initialized; + int finalizing; + uint64_t monitoring_version; uint64_t last_restart_version; - struct pythreads { uint64_t next_unique_id; /* The linked list of threads, newest first. */ @@ -72,18 +82,6 @@ struct _is { Get runtime from tstate: tstate->interp->runtime. */ struct pyruntimestate *runtime; - int64_t id; - int64_t id_refcount; - int requires_idref; - PyThread_type_lock id_mutex; - - /* Has been initialized to a safe state. - - In order to be effective, this must be set to 0 during or right - after allocation. */ - int _initialized; - int finalizing; - /* Set by Py_EndInterpreter(). Use _PyInterpreterState_GetFinalizing() @@ -91,17 +89,33 @@ struct _is { to access it, don't access it directly. */ _Py_atomic_address _finalizing; - struct _obmalloc_state obmalloc; - struct _gc_runtime_state gc; - struct _import_state imports; + /* The following fields are here to avoid allocation during init. + The data is exposed through PyInterpreterState pointer fields. + These fields should not be accessed directly outside of init. + + All other PyInterpreterState pointer fields are populated when + needed and default to NULL. + + For now there are some exceptions to that rule, which require + allocation during init. These will be addressed on a case-by-case + basis. Also see _PyRuntimeState regarding the various mutex fields. + */ + + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; // Dictionary of the sys module PyObject *sysdict; // Dictionary of the builtins module PyObject *builtins; + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + PyObject *codec_search_path; PyObject *codec_search_cache; PyObject *codec_error_registry; @@ -133,6 +147,12 @@ struct _is { struct _warnings_runtime_state warnings; struct atexit_state atexit; + struct _ceval_state ceval; + + struct _obmalloc_state obmalloc; + + struct _import_state imports; + PyObject *audit_hooks; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; @@ -175,22 +195,7 @@ struct _is { struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; - /* The following fields are here to avoid allocation during init. - The data is exposed through PyInterpreterState pointer fields. - These fields should not be accessed directly outside of init. - - All other PyInterpreterState pointer fields are populated when - needed and default to NULL. - - For now there are some exceptions to that rule, which require - allocation during init. These will be addressed on a case-by-case - basis. Also see _PyRuntimeState regarding the various mutex fields. - */ - - /* The per-interpreter GIL, which might not be used. */ - struct _gil_runtime_state _gil; - - /* the initial PyInterpreterState.threads.head */ + /* the initial PyInterpreterState.threads.head */ PyThreadState _initial_thread; }; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 8f51e2def69fc9..5ed97e9715b2b0 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -84,13 +84,6 @@ typedef struct pyruntimestate { to access it, don't access it directly. */ _Py_atomic_address _finalizing; - struct _pymem_allocators allocators; - struct _obmalloc_global_state obmalloc; - struct pyhash_runtime_state pyhash_state; - struct _time_runtime_state time; - struct _pythread_runtime_state threads; - struct _signals_runtime_state signals; - struct pyinterpreters { PyThread_type_lock mutex; /* The linked list of interpreters, newest first. */ @@ -109,13 +102,26 @@ typedef struct pyruntimestate { using a Python int. */ int64_t next_id; } interpreters; + + unsigned long main_thread; + + /* ---------- IMPORTANT --------------------------- + The fields above this line are declared as early as + possible to facilitate out-of-process observability + tools. */ + // XXX Remove this field once we have a tp_* slot. struct _xidregistry { PyThread_type_lock mutex; struct _xidregitem *head; } xidregistry; - unsigned long main_thread; + struct _pymem_allocators allocators; + struct _obmalloc_global_state obmalloc; + struct pyhash_runtime_state pyhash_state; + struct _time_runtime_state time; + struct _pythread_runtime_state threads; + struct _signals_runtime_state signals; /* Used for the thread state bound to the current thread. */ Py_tss_t autoTSSkey; From 9126a6a9ce3772d5dc785cbee159b07a1ff7d531 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 27 Jun 2023 17:09:15 +0100 Subject: [PATCH 158/446] gh-106140: Reorder some more fields to facilitate out-of-process inspection (#106148) --- Include/internal/pycore_interp.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 8d0bb7672690a8..466ae6fbbdc4eb 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -103,14 +103,19 @@ struct _is { basis. Also see _PyRuntimeState regarding the various mutex fields. */ - /* The per-interpreter GIL, which might not be used. */ - struct _gil_runtime_state _gil; - // Dictionary of the sys module PyObject *sysdict; + // Dictionary of the builtins module PyObject *builtins; + struct _ceval_state ceval; + + struct _import_state imports; + + /* The per-interpreter GIL, which might not be used. */ + struct _gil_runtime_state _gil; + /* ---------- IMPORTANT --------------------------- The fields above this line are declared as early as possible to facilitate out-of-process observability @@ -147,12 +152,8 @@ struct _is { struct _warnings_runtime_state warnings; struct atexit_state atexit; - struct _ceval_state ceval; - struct _obmalloc_state obmalloc; - struct _import_state imports; - PyObject *audit_hooks; PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS]; PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS]; From eaa1eae55ea66d74c5303924320185dac74d4eb1 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 27 Jun 2023 13:12:56 -0400 Subject: [PATCH 159/446] IDLE: Condense run.main threading.Thread start. (#106125) Use daemon argument added in 3.3 and directly call .start. Remove now unused 'sockthread' name. --- Lib/idlelib/run.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 4ffc90ab0c852a..53e80a9b42801f 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -140,11 +140,12 @@ def main(del_exitfunc=False): capture_warnings(True) sys.argv[:] = [""] - sockthread = threading.Thread(target=manage_socket, - name='SockThread', - args=((LOCALHOST, port),)) - sockthread.daemon = True - sockthread.start() + threading.Thread(target=manage_socket, + name='SockThread', + args=((LOCALHOST, port),), + daemon=True, + ).start() + while True: try: if exit_now: From 529088100952b31797a29ef7e0f5716613b32d66 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:24:58 +0100 Subject: [PATCH 160/446] gh-106149: move jump target resolution from optimizer to assembler (#106150) --- Include/internal/pycore_compile.h | 8 +- Include/internal/pycore_flowgraph.h | 2 - Python/assemble.c | 111 +++++++++++++++++++++++++--- Python/compile.c | 17 ++--- Python/flowgraph.c | 80 +------------------- 5 files changed, 113 insertions(+), 105 deletions(-) diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index e6481734a675c6..e204d4d2457a16 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -28,7 +28,7 @@ extern int _PyAST_Optimize( int ff_features); typedef struct { - int h_offset; + int h_label; int h_startdepth; int h_preserve_lasti; } _PyCompile_ExceptHandlerInfo; @@ -38,6 +38,10 @@ typedef struct { int i_oparg; _PyCompilerSrcLocation i_loc; _PyCompile_ExceptHandlerInfo i_except_handler_info; + + /* Used by the assembler */ + int i_target; + int i_offset; } _PyCompile_Instruction; typedef struct { @@ -85,8 +89,6 @@ int _PyCompile_EnsureArrayLargeEnough( int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj); -int _PyCompile_InstrSize(int opcode, int oparg); - /* Access compiler internals for unit testing */ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen( diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h index 720feb18636959..4a01574809fff5 100644 --- a/Include/internal/pycore_flowgraph.h +++ b/Include/internal/pycore_flowgraph.h @@ -55,8 +55,6 @@ typedef struct _PyCfgBasicblock_ { int b_predecessors; /* depth of stack upon entry of block, computed by stackdepth() */ int b_startdepth; - /* instruction offset for block, computed by assemble_jump_offsets() */ - int b_offset; /* Basic block is an exception handler that preserves lasti */ unsigned b_preserve_lasti : 1; /* Used by compiler passes to mark whether they have visited a basic block. */ diff --git a/Python/assemble.c b/Python/assemble.c index d6213f89e7bf75..5d566a381b3988 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -4,6 +4,7 @@ #include "pycore_code.h" // write_location_entry_start() #include "pycore_compile.h" #include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros +#include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE #include "opcode_metadata.h" // IS_PSEUDO_INSTR @@ -34,6 +35,18 @@ same_location(location a, location b) a.end_col_offset == b.end_col_offset; } +static int +instr_size(instruction *instr) +{ + int opcode = instr->i_opcode; + int oparg = instr->i_oparg; + assert(!IS_PSEUDO_INSTR(opcode)); + assert(OPCODE_HAS_ARG(opcode) || oparg == 0); + int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); + int caches = _PyOpcode_Caches[opcode]; + return extended_args + 1 + caches; +} + struct assembler { PyObject *a_bytecode; /* bytes containing bytecode */ int a_offset; /* offset into bytecode */ @@ -118,6 +131,7 @@ assemble_emit_exception_table_item(struct assembler *a, int value, int msb) static int assemble_emit_exception_table_entry(struct assembler *a, int start, int end, + int handler_offset, _PyCompile_ExceptHandlerInfo *handler) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); @@ -126,7 +140,7 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, } int size = end-start; assert(end > start); - int target = handler->h_offset; + int target = handler_offset; int depth = handler->h_startdepth - 1; if (handler->h_preserve_lasti > 0) { depth -= 1; @@ -145,24 +159,30 @@ assemble_exception_table(struct assembler *a, instr_sequence *instrs) { int ioffset = 0; _PyCompile_ExceptHandlerInfo handler; - handler.h_offset = -1; + handler.h_label = -1; handler.h_startdepth = -1; handler.h_preserve_lasti = -1; int start = -1; for (int i = 0; i < instrs->s_used; i++) { instruction *instr = &instrs->s_instrs[i]; - if (instr->i_except_handler_info.h_offset != handler.h_offset) { - if (handler.h_offset >= 0) { + if (instr->i_except_handler_info.h_label != handler.h_label) { + if (handler.h_label >= 0) { + int handler_offset = instrs->s_instrs[handler.h_label].i_offset; RETURN_IF_ERROR( - assemble_emit_exception_table_entry(a, start, ioffset, &handler)); + assemble_emit_exception_table_entry(a, start, ioffset, + handler_offset, + &handler)); } start = ioffset; handler = instr->i_except_handler_info; } - ioffset += _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); + ioffset += instr_size(instr); } - if (handler.h_offset >= 0) { - RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, &handler)); + if (handler.h_label >= 0) { + int handler_offset = instrs->s_instrs[handler.h_label].i_offset; + RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, + handler_offset, + &handler)); } return SUCCESS; } @@ -329,7 +349,7 @@ assemble_location_info(struct assembler *a, instr_sequence *instrs, loc = instr->i_loc; size = 0; } - size += _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); + size += instr_size(instr); } RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); return SUCCESS; @@ -385,7 +405,7 @@ assemble_emit_instr(struct assembler *a, instruction *instr) Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; - int size = _PyCompile_InstrSize(instr->i_opcode, instr->i_oparg); + int size = instr_size(instr); if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) { if (len > PY_SSIZE_T_MAX / 2) { return ERROR; @@ -585,12 +605,83 @@ makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_ return co; } +static int +resolve_jump_offsets(instr_sequence *instrs) +{ + /* Compute the size of each instruction and fixup jump args. + * Replace instruction index with position in bytecode. + */ + + for (int i = 0; i < instrs->s_used; i++) { + instruction *instr = &instrs->s_instrs[i]; + if (OPCODE_HAS_JUMP(instr->i_opcode)) { + instr->i_target = instr->i_oparg; + } + } + + int extended_arg_recompile; + + do { + int totsize = 0; + for (int i = 0; i < instrs->s_used; i++) { + instruction *instr = &instrs->s_instrs[i]; + instr->i_offset = totsize; + int isize = instr_size(instr); + totsize += isize; + } + extended_arg_recompile = 0; + + int offset = 0; + for (int i = 0; i < instrs->s_used; i++) { + instruction *instr = &instrs->s_instrs[i]; + int isize = instr_size(instr); + /* jump offsets are computed relative to + * the instruction pointer after fetching + * the jump instruction. + */ + offset += isize; + if (OPCODE_HAS_JUMP(instr->i_opcode)) { + instruction *target = &instrs->s_instrs[instr->i_target]; + instr->i_oparg = target->i_offset; + if (instr->i_oparg < offset) { + assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg = offset - instr->i_oparg; + } + else { + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg = instr->i_oparg - offset; + } + if (instr_size(instr) != isize) { + extended_arg_recompile = 1; + } + } + } + /* XXX: This is an awful hack that could hurt performance, but + on the bright side it should work until we come up + with a better solution. + + The issue is that in the first loop instr_size() is + called, and it requires i_oparg be set appropriately. + There is a bootstrap problem because i_oparg is + calculated in the second loop above. + + So we loop until we stop seeing new EXTENDED_ARGs. + The only EXTENDED_ARGs that could be popping up are + ones in jump instructions. So this should converge + fairly quickly. + */ + } while (extended_arg_recompile); + return SUCCESS; +} PyCodeObject * _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache, PyObject *consts, int maxdepth, instr_sequence *instrs, int nlocalsplus, int code_flags, PyObject *filename) { + if (resolve_jump_offsets(instrs) < 0) { + return NULL; + } PyCodeObject *co = NULL; struct assembler a; diff --git a/Python/compile.c b/Python/compile.c index 5a0560521b99d5..d080144121af7b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -131,16 +131,6 @@ enum { }; -int -_PyCompile_InstrSize(int opcode, int oparg) -{ - assert(!IS_PSEUDO_INSTR(opcode)); - assert(OPCODE_HAS_ARG(opcode) || oparg == 0); - int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); - int caches = _PyOpcode_Caches[opcode]; - return extended_args + 1 + caches; -} - typedef _PyCompile_Instruction instruction; typedef _PyCompile_InstructionSequence instr_sequence; @@ -7717,17 +7707,20 @@ cfg_to_instr_sequence(cfg_builder *g, instr_sequence *seq) RETURN_IF_ERROR(instr_sequence_use_label(seq, b->b_label.id)); for (int i = 0; i < b->b_iused; i++) { cfg_instr *instr = &b->b_instr[i]; + if (OPCODE_HAS_JUMP(instr->i_opcode)) { + instr->i_oparg = instr->i_target->b_label.id; + } RETURN_IF_ERROR( instr_sequence_addop(seq, instr->i_opcode, instr->i_oparg, instr->i_loc)); _PyCompile_ExceptHandlerInfo *hi = &seq->s_instrs[seq->s_used-1].i_except_handler_info; if (instr->i_except != NULL) { - hi->h_offset = instr->i_except->b_offset; + hi->h_label = instr->i_except->b_label.id; hi->h_startdepth = instr->i_except->b_startdepth; hi->h_preserve_lasti = instr->i_except->b_preserve_lasti; } else { - hi->h_offset = -1; + hi->h_label = -1; } } } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 39f780e60220a1..a6b2a9f275a70a 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -166,22 +166,6 @@ _PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) { return SUCCESS; } -static int -instr_size(cfg_instr *instruction) -{ - return _PyCompile_InstrSize(instruction->i_opcode, instruction->i_oparg); -} - -static int -blocksize(basicblock *b) -{ - int size = 0; - for (int i = 0; i < b->b_iused; i++) { - size += instr_size(&b->b_instr[i]); - } - return size; -} - /* For debugging purposes only */ #if 0 static void @@ -212,9 +196,9 @@ static void dump_basicblock(const basicblock *b) { const char *b_return = basicblock_returns(b) ? "return " : ""; - fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", + fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, %s\n", b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, - b->b_startdepth, b->b_offset, b_return); + b->b_startdepth, b_return); if (b->b_instr) { int i; for (i = 0; i < b->b_iused; i++) { @@ -480,71 +464,11 @@ normalize_jumps(_PyCfgBuilder *g) return SUCCESS; } -static void -resolve_jump_offsets(basicblock *entryblock) -{ - int bsize, totsize, extended_arg_recompile; - - /* Compute the size of each block and fixup jump args. - Replace block pointer with position in bytecode. */ - do { - totsize = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - bsize = blocksize(b); - b->b_offset = totsize; - totsize += bsize; - } - extended_arg_recompile = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - bsize = b->b_offset; - for (int i = 0; i < b->b_iused; i++) { - cfg_instr *instr = &b->b_instr[i]; - int isize = instr_size(instr); - /* jump offsets are computed relative to - * the instruction pointer after fetching - * the jump instruction. - */ - bsize += isize; - if (is_jump(instr)) { - instr->i_oparg = instr->i_target->b_offset; - if (instr->i_oparg < bsize) { - assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg = bsize - instr->i_oparg; - } - else { - assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg -= bsize; - } - if (instr_size(instr) != isize) { - extended_arg_recompile = 1; - } - } - } - } - - /* XXX: This is an awful hack that could hurt performance, but - on the bright side it should work until we come up - with a better solution. - - The issue is that in the first loop blocksize() is called - which calls instr_size() which requires i_oparg be set - appropriately. There is a bootstrap problem because - i_oparg is calculated in the second loop above. - - So we loop until we stop seeing new EXTENDED_ARGs. - The only EXTENDED_ARGs that could be popping up are - ones in jump instructions. So this should converge - fairly quickly. - */ - } while (extended_arg_recompile); -} - int _PyCfg_ResolveJumps(_PyCfgBuilder *g) { RETURN_IF_ERROR(normalize_jumps(g)); assert(no_redundant_jumps(g)); - resolve_jump_offsets(g->g_entryblock); return SUCCESS; } From 6b5166fb12c4744544da4ee26ef437d025eb762a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 27 Jun 2023 14:17:41 -0700 Subject: [PATCH 161/446] gh-104584: Change DEOPT_IF in uops executor (#106146) This effectively reverts bb578a0, restoring the original DEOPT_IF() macro in ceval_macros.h, and redefining it in the Tier 2 interpreter. We can get rid of the PREDICTED() macros there as well! --- Python/ceval.c | 16 ++++++---------- Python/ceval_macros.h | 3 +-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 3e0dcf8c8629b9..e19860d04a7914 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2767,10 +2767,11 @@ void Py_LeaveRecursiveCall(void) ///////////////////// Experimental UOp Interpreter ///////////////////// -// UPDATE_MISS_STATS (called by DEOPT_IF) uses next_instr -// TODO: Make it do something useful -#undef UPDATE_MISS_STATS -#define UPDATE_MISS_STATS(INSTNAME) ((void)0) +#undef DEOPT_IF +#define DEOPT_IF(COND, INSTNAME) \ + if ((COND)) { \ + goto deoptimize; \ + } _PyInterpreterFrame * _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer) @@ -2875,12 +2876,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject Py_DECREF(self); return NULL; -PREDICTED(UNPACK_SEQUENCE) -PREDICTED(COMPARE_OP) -PREDICTED(LOAD_SUPER_ATTR) -PREDICTED(STORE_SUBSCR) -PREDICTED(BINARY_SUBSCR) -PREDICTED(BINARY_OP) +deoptimize: // On DEOPT_IF we just repeat the last instruction. // This presumes nothing was popped from the stack (nor pushed). #ifdef LLTRACE diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index f5c78fc65e1745..0d41ef5a14cef4 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -264,12 +264,11 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define UPDATE_MISS_STATS(INSTNAME) ((void)0) #endif -// NOTE: in the uops version, opcode may be > 255 #define DEOPT_IF(COND, INSTNAME) \ if ((COND)) { \ /* This is only a single jump on release builds! */ \ UPDATE_MISS_STATS((INSTNAME)); \ - assert(opcode >= 256 || _PyOpcode_Deopt[opcode] == (INSTNAME)); \ + assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \ GO_TO_INSTRUCTION(INSTNAME); \ } From 84caa3324aaefb900895de2f946607cfdbe1be70 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 01:34:37 +0200 Subject: [PATCH 162/446] gh-106084: Remove _PyObject_CallMethod() function (#106159) Remove the following private functions from the public C API: * _Py_CheckFunctionResult() * _PyObject_CallMethod() * _PyObject_CallMethodId() * _PyObject_CallMethodIdNoArgs() * _PyObject_CallMethodIdObjArgs() * _PyObject_CallMethodIdOneArg() * _PyObject_MakeTpCall() * _PyObject_VectorcallMethodId() * _PyStack_AsDict() Move these functions to the internal C API (pycore_call.h). No longer export the following functions: * _PyObject_Call() * _PyObject_CallMethod() * _PyObject_CallMethodId() * _PyObject_CallMethodIdObjArgs() * _PyObject_Call_Prepend() * _PyObject_FastCallDictTstate() * _PyStack_AsDict() The following functions are still exported for stdlib shared extensions: * _Py_CheckFunctionResult() * _PyObject_MakeTpCall() Mark the following internal functions as extern: * _PyStack_UnpackDict() * _PyStack_UnpackDict_Free() * _PyStack_UnpackDict_FreeNoDecRef() --- Include/cpython/abstract.h | 74 +---------------------- Include/internal/pycore_call.h | 105 ++++++++++++++++++++++++++++++--- Modules/_bisectmodule.c | 5 ++ Modules/_io/iobase.c | 3 +- Modules/_io/textio.c | 3 +- Modules/arraymodule.c | 1 + Objects/descrobject.c | 1 + Objects/methodobject.c | 1 + Python/pylifecycle.c | 3 +- 9 files changed, 111 insertions(+), 85 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 5eb22ff61ecddc..2e76ff49a81dd3 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -4,20 +4,6 @@ /* === Object Protocol ================================================== */ -/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple) - format to a Python dictionary ("kwargs" dict). - - The type of kwnames keys is not checked. The final function getting - arguments is responsible to check if all keys are strings, for example using - PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments(). - - Duplicate keys are merged using the last value. If duplicate keys must raise - an exception, the caller is responsible to implement an explicit keys on - kwnames. */ -PyAPI_FUNC(PyObject *) _PyStack_AsDict( - PyObject *const *values, - PyObject *kwnames); - /* Suggested size (number of positional arguments) for arrays of PyObject* allocated on a C stack to avoid allocating memory on the heap memory. Such array is used to pass positional arguments to call functions of the @@ -29,32 +15,17 @@ PyAPI_FUNC(PyObject *) _PyStack_AsDict( 40 bytes on the stack. */ #define _PY_FASTCALL_SMALL_STACK 5 -PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult( - PyThreadState *tstate, - PyObject *callable, - PyObject *result, - const char *where); - /* === Vectorcall protocol (PEP 590) ============================= */ -/* Call callable using tp_call. Arguments are like PyObject_Vectorcall() - or PyObject_FastCallDict() (both forms are supported), - except that nargs is plainly the number of arguments without flags. */ -PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall( - PyThreadState *tstate, - PyObject *callable, - PyObject *const *args, Py_ssize_t nargs, - PyObject *keywords); - // PyVectorcall_NARGS() is exported as a function for the stable ABI. // Here (when we are not using the stable ABI), the name is overridden to // call a static inline function for best performance. -#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n) static inline Py_ssize_t _PyVectorcall_NARGS(size_t n) { return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; } +#define PyVectorcall_NARGS(n) _PyVectorcall_NARGS(n) PyAPI_FUNC(vectorcallfunc) PyVectorcall_Function(PyObject *callable); @@ -90,49 +61,6 @@ PyObject_CallMethodOneArg(PyObject *self, PyObject *name, PyObject *arg) return PyObject_VectorcallMethod(name, args, nargsf, _Py_NULL); } -PyAPI_FUNC(PyObject *) _PyObject_CallMethod(PyObject *obj, - PyObject *name, - const char *format, ...); - -/* Like PyObject_CallMethod(), but expect a _Py_Identifier* - as the method name. */ -PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj, - _Py_Identifier *name, - const char *format, ...); - -PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs( - PyObject *obj, - _Py_Identifier *name, - ...); - -static inline PyObject * -_PyObject_VectorcallMethodId( - _Py_Identifier *name, PyObject *const *args, - size_t nargsf, PyObject *kwnames) -{ - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - return _Py_NULL; - } - return PyObject_VectorcallMethod(oname, args, nargsf, kwnames); -} - -static inline PyObject * -_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name) -{ - size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET; - return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL); -} - -static inline PyObject * -_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg) -{ - PyObject *args[2] = {self, arg}; - size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET; - assert(arg != NULL); - return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL); -} - /* Guess the size of object 'o' using len(o) or o.__length_hint__(). If neither of those return a non-negative value, then return the default value. If one of the calls fails, this function returns -1. */ diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 5d9342b562b002..3caf504a96aa3a 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -10,29 +10,112 @@ extern "C" { #include "pycore_pystate.h" // _PyThreadState_GET() -PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend( +// Export for shared stdlib extensions like the math extension, +// function used via inlined _PyObject_VectorcallTstate() function. +PyAPI_FUNC(PyObject*) _Py_CheckFunctionResult( + PyThreadState *tstate, + PyObject *callable, + PyObject *result, + const char *where); + +/* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple) + format to a Python dictionary ("kwargs" dict). + + The type of kwnames keys is not checked. The final function getting + arguments is responsible to check if all keys are strings, for example using + PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments(). + + Duplicate keys are merged using the last value. If duplicate keys must raise + an exception, the caller is responsible to implement an explicit keys on + kwnames. */ +extern PyObject* _PyStack_AsDict(PyObject *const *values, PyObject *kwnames); + +extern PyObject* _PyObject_Call_Prepend( PyThreadState *tstate, PyObject *callable, PyObject *obj, PyObject *args, PyObject *kwargs); -PyAPI_FUNC(PyObject *) _PyObject_FastCallDictTstate( +extern PyObject* _PyObject_FastCallDictTstate( PyThreadState *tstate, PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwargs); -PyAPI_FUNC(PyObject *) _PyObject_Call( +extern PyObject* _PyObject_Call( PyThreadState *tstate, PyObject *callable, PyObject *args, PyObject *kwargs); extern PyObject * _PyObject_CallMethodFormat( - PyThreadState *tstate, PyObject *callable, const char *format, ...); + PyThreadState *tstate, + PyObject *callable, + const char *format, + ...); +// Export for shared stdlib extensions like the array extension +PyAPI_FUNC(PyObject*) _PyObject_CallMethod( + PyObject *obj, + PyObject *name, + const char *format, ...); + +/* Like PyObject_CallMethod(), but expect a _Py_Identifier* + as the method name. */ +extern PyObject* _PyObject_CallMethodId( + PyObject *obj, + _Py_Identifier *name, + const char *format, ...); + +extern PyObject* _PyObject_CallMethodIdObjArgs( + PyObject *obj, + _Py_Identifier *name, + ...); + +static inline PyObject * +_PyObject_VectorcallMethodId( + _Py_Identifier *name, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ + if (!oname) { + return _Py_NULL; + } + return PyObject_VectorcallMethod(oname, args, nargsf, kwnames); +} + +static inline PyObject * +_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name) +{ + size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET; + return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL); +} + +static inline PyObject * +_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg) +{ + PyObject *args[2] = {self, arg}; + size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET; + assert(arg != NULL); + return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL); +} + + +/* === Vectorcall protocol (PEP 590) ============================= */ + +// Call callable using tp_call. Arguments are like PyObject_Vectorcall() +// or PyObject_FastCallDict() (both forms are supported), +// except that nargs is plainly the number of arguments without flags. +// +// Export for shared stdlib extensions like the math extension, +// function used via inlined _PyObject_VectorcallTstate() function. +PyAPI_FUNC(PyObject*) _PyObject_MakeTpCall( + PyThreadState *tstate, + PyObject *callable, + PyObject *const *args, Py_ssize_t nargs, + PyObject *keywords); // Static inline variant of public PyVectorcall_Function(). static inline vectorcallfunc @@ -110,22 +193,26 @@ _PyObject_CallNoArgs(PyObject *func) { static inline PyObject * -_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, PyObject *const *args, Py_ssize_t nargs) +_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, + PyObject *const *args, Py_ssize_t nargs) { EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func); return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL); } -PyObject *const * +extern PyObject *const * _PyStack_UnpackDict(PyThreadState *tstate, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs, PyObject **p_kwnames); -void -_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs, +extern void _PyStack_UnpackDict_Free( + PyObject *const *stack, + Py_ssize_t nargs, PyObject *kwnames); -void _PyStack_UnpackDict_FreeNoDecRef(PyObject *const *stack, PyObject *kwnames); +extern void _PyStack_UnpackDict_FreeNoDecRef( + PyObject *const *stack, + PyObject *kwnames); #ifdef __cplusplus } diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 0773bbd191931d..60f4dc69dc05d9 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -3,8 +3,13 @@ Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru). */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_call.h" // _PyObject_CallMethod() /*[clinic input] module _bisect diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index f98e75ce2d1ed3..5cd679c68b1281 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -10,8 +10,9 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_long.h" // _PyLong_GetOne() -#include "pycore_object.h" +#include "pycore_object.h" // _PyType_HasFeature() #include // offsetof() #include "_iomodule.h" diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 0ea7458df559bb..e6b1306c2f3f0b 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -8,10 +8,11 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_fileutils.h" // _Py_GetLocaleEncoding() -#include "pycore_object.h" +#include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "structmember.h" // PyMemberDef #include "_iomodule.h" diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 8132689c66c0af..15f7766a8dd284 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -9,6 +9,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_bytesobject.h" // _PyBytes_Repeat #include "structmember.h" // PyMemberDef diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 89bac99bb9d638..a81490285eed4a 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyObject_RealIsSubclass() +#include "pycore_call.h" // _PyStack_AsDict() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pystate.h" // _PyThreadState_GET() diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 51752dec3dd08c..fe081992d51fda 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -2,6 +2,7 @@ /* Method object implementation */ #include "Python.h" +#include "pycore_call.h" // _Py_CheckFunctionResult() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" #include "pycore_pyerrors.h" diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 6117f3a19a5509..1df35ef4278677 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2,10 +2,11 @@ #include "Python.h" +#include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() #include "pycore_context.h" // _PyContext_Init() -#include "pycore_exceptions.h" // _PyExc_InitTypes() #include "pycore_dict.h" // _PyDict_Fini() +#include "pycore_exceptions.h" // _PyExc_InitTypes() #include "pycore_fileutils.h" // _Py_ResetForceASCII() #include "pycore_floatobject.h" // _PyFloat_InitTypes() #include "pycore_genobject.h" // _PyAsyncGen_Fini() From 161012fc25910a47423bae8012398bf519a88140 Mon Sep 17 00:00:00 2001 From: "T. Wouters" Date: Wed, 28 Jun 2023 02:55:11 +0200 Subject: [PATCH 163/446] GH-106160: Fix test_gzip failing under WASI, which does not have zlib. (#106167) Fix test_gzip's failure under WASI, which does not have zlib, by using test.support.import_helper.import_module to import zlib. (gzip unconditionally imports zlib, so this does not cause any new skips.) --- Lib/test/test_gzip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_gzip.py b/Lib/test/test_gzip.py index c7ac7c687c8b2d..b06b3b09411d62 100644 --- a/Lib/test/test_gzip.py +++ b/Lib/test/test_gzip.py @@ -9,7 +9,6 @@ import struct import sys import unittest -import zlib from subprocess import PIPE, Popen from test.support import import_helper from test.support import os_helper @@ -17,6 +16,7 @@ from test.support.script_helper import assert_python_ok, assert_python_failure gzip = import_helper.import_module('gzip') +zlib = import_helper.import_module('zlib') data1 = b""" int length=DEFAULTALLOC, err = Z_OK; PyObject *RetVal; From 3f8483cad2f3b94600c3ecf3f0bb220bb1e61d7d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 03:45:57 +0200 Subject: [PATCH 164/446] gh-106168: PyTuple_SET_ITEM() now checks the index (#106164) PyTuple_SET_ITEM() and PyList_SET_ITEM() now check the index argument with an assertion if Python is built in debug mode or is built with assertions. * list_extend() and _PyList_AppendTakeRef() now set the list size before calling PyList_SET_ITEM(). * PyStructSequence_GetItem() and PyStructSequence_SetItem() now check the index argument: must be lesser than REAL_SIZE(op). * PyStructSequence_GET_ITEM() and PyStructSequence_SET_ITEM() are now aliases to PyStructSequence_GetItem() and PyStructSequence_SetItem(). --- Doc/c-api/list.rst | 4 ++++ Doc/c-api/tuple.rst | 23 +++++++++++++------ Doc/whatsnew/3.13.rst | 6 +++++ Include/cpython/listobject.h | 2 ++ Include/cpython/tupleobject.h | 2 ++ Include/internal/pycore_list.h | 2 +- Include/structseq.h | 13 ++++------- ...-06-28-02-30-50.gh-issue-106168.NFOZPv.rst | 5 ++++ Objects/listobject.c | 5 ++-- Objects/structseq.c | 23 +++++++++++++++---- 10 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-28-02-30-50.gh-issue-106168.NFOZPv.rst diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index dbf35611eccd3e..c15cecd41b89d1 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -86,6 +86,10 @@ List Objects Macro form of :c:func:`PyList_SetItem` without error checking. This is normally only used to fill in new lists where there is no previous content. + Bounds checking is performed as an assertion if Python is built in + :ref:`debug mode ` or :option:`with assertions + <--with-assertions>`. + .. note:: This macro "steals" a reference to *item*, and, unlike diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index ac62058676eeeb..3fe1062aa8539a 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -89,6 +89,9 @@ Tuple Objects Like :c:func:`PyTuple_SetItem`, but does no error checking, and should *only* be used to fill in brand new tuples. + Bounds checking is performed as an assertion if Python is built in + :ref:`debug mode ` or :option:`with assertions <--with-assertions>`. + .. note:: This function "steals" a reference to *o*, and, unlike @@ -194,12 +197,17 @@ type. .. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos) Return the object at position *pos* in the struct sequence pointed to by *p*. - No bounds checking is performed. + + Bounds checking is performed as an assertion if Python is built in + :ref:`debug mode ` or :option:`with assertions <--with-assertions>`. .. c:function:: PyObject* PyStructSequence_GET_ITEM(PyObject *p, Py_ssize_t pos) - Macro equivalent of :c:func:`PyStructSequence_GetItem`. + Alias to :c:func:`PyStructSequence_GetItem`. + + .. versionchanged:: 3.13 + Now implemented as an alias to :c:func:`PyStructSequence_GetItem`. .. c:function:: void PyStructSequence_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o) @@ -208,6 +216,9 @@ type. :c:func:`PyTuple_SET_ITEM`, this should only be used to fill in brand new instances. + Bounds checking is performed as an assertion if Python is built in + :ref:`debug mode ` or :option:`with assertions <--with-assertions>`. + .. note:: This function "steals" a reference to *o*. @@ -215,9 +226,7 @@ type. .. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o) - Similar to :c:func:`PyStructSequence_SetItem`, but implemented as a static - inlined function. + Alias to :c:func:`PyStructSequence_SetItem`. - .. note:: - - This function "steals" a reference to *o*. + .. versionchanged:: 3.13 + Now implemented as an alias to :c:func:`PyStructSequence_SetItem`. diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index f3460beeb16be6..c0e9e924c8e82f 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -441,6 +441,12 @@ New Features ``NULL`` if the referent is no longer live. (Contributed by Victor Stinner in :gh:`105927`.) +* If Python is built in :ref:`debug mode ` or :option:`with + assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and + :c:func:`PyList_SET_ITEM` now check the index argument with an assertion. + If the assertion fails, make sure that the size is set before. + (Contributed by Victor Stinner in :gh:`106168`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/cpython/listobject.h b/Include/cpython/listobject.h index 8fa82122d8d248..b3b23985de7a66 100644 --- a/Include/cpython/listobject.h +++ b/Include/cpython/listobject.h @@ -41,6 +41,8 @@ static inline Py_ssize_t PyList_GET_SIZE(PyObject *op) { static inline void PyList_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) { PyListObject *list = _PyList_CAST(op); + assert(0 <= index); + assert(index < Py_SIZE(list)); list->ob_item[index] = value; } #define PyList_SET_ITEM(op, index, value) \ diff --git a/Include/cpython/tupleobject.h b/Include/cpython/tupleobject.h index f6a1f076e03330..370da1612a61ed 100644 --- a/Include/cpython/tupleobject.h +++ b/Include/cpython/tupleobject.h @@ -31,6 +31,8 @@ static inline Py_ssize_t PyTuple_GET_SIZE(PyObject *op) { static inline void PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) { PyTupleObject *tuple = _PyTuple_CAST(op); + assert(0 <= index); + assert(index < Py_SIZE(tuple)); tuple->ob_item[index] = value; } #define PyTuple_SET_ITEM(op, index, value) \ diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 2fcbe12cd6559e..b2e503c87542bf 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -49,8 +49,8 @@ _PyList_AppendTakeRef(PyListObject *self, PyObject *newitem) Py_ssize_t allocated = self->allocated; assert((size_t)len + 1 < PY_SSIZE_T_MAX); if (allocated > len) { - PyList_SET_ITEM(self, len, newitem); Py_SET_SIZE(self, len + 1); + PyList_SET_ITEM(self, len, newitem); return 0; } return _PyList_AppendTakeRefListResize(self, newitem); diff --git a/Include/structseq.h b/Include/structseq.h index 96871155611958..29e24fee54e613 100644 --- a/Include/structseq.h +++ b/Include/structseq.h @@ -31,18 +31,15 @@ PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); +PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); +PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); + #ifndef Py_LIMITED_API typedef PyTupleObject PyStructSequence; - -/* Macro, *only* to be used to fill in brand new objects */ -#define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM((op), (i), (v)) - -#define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM((op), (i)) +#define PyStructSequence_SET_ITEM PyStructSequence_SetItem +#define PyStructSequence_GET_ITEM PyStructSequence_GetItem #endif -PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*); -PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); - #ifdef __cplusplus } #endif diff --git a/Misc/NEWS.d/next/C API/2023-06-28-02-30-50.gh-issue-106168.NFOZPv.rst b/Misc/NEWS.d/next/C API/2023-06-28-02-30-50.gh-issue-106168.NFOZPv.rst new file mode 100644 index 00000000000000..741d709bf824b8 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-28-02-30-50.gh-issue-106168.NFOZPv.rst @@ -0,0 +1,5 @@ +If Python is built in :ref:`debug mode ` or :option:`with +assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and +:c:func:`PyList_SET_ITEM` now check the index argument with an assertion. If +the assertion fails, make sure that the size is set before. Patch by Victor +Stinner. diff --git a/Objects/listobject.c b/Objects/listobject.c index f1edfb3a9a039d..f1f324f7439b43 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -953,8 +953,9 @@ list_extend(PyListObject *self, PyObject *iterable) } if (Py_SIZE(self) < self->allocated) { /* steals ref */ - PyList_SET_ITEM(self, Py_SIZE(self), item); - Py_SET_SIZE(self, Py_SIZE(self) + 1); + Py_ssize_t len = Py_SIZE(self); + Py_SET_SIZE(self, len + 1); + PyList_SET_ITEM(self, len, item); } else { if (_PyList_AppendTakeRef(self, item) < 0) diff --git a/Objects/structseq.c b/Objects/structseq.c index 8b1895957101a4..49011139b66534 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -74,15 +74,28 @@ PyStructSequence_New(PyTypeObject *type) } void -PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v) +PyStructSequence_SetItem(PyObject *op, Py_ssize_t index, PyObject *value) { - PyStructSequence_SET_ITEM(op, i, v); + PyTupleObject *tuple = _PyTuple_CAST(op); + assert(0 <= index); +#ifndef NDEBUG + Py_ssize_t n_fields = REAL_SIZE(op); + assert(n_fields >= 0); + assert(index < n_fields); +#endif + tuple->ob_item[index] = value; } PyObject* -PyStructSequence_GetItem(PyObject* op, Py_ssize_t i) +PyStructSequence_GetItem(PyObject *op, Py_ssize_t index) { - return PyStructSequence_GET_ITEM(op, i); + assert(0 <= index); +#ifndef NDEBUG + Py_ssize_t n_fields = REAL_SIZE(op); + assert(n_fields >= 0); + assert(index < n_fields); +#endif + return PyTuple_GET_ITEM(op, index); } @@ -287,7 +300,7 @@ structseq_repr(PyStructSequence *obj) goto error; } - PyObject *value = PyStructSequence_GET_ITEM(obj, i); + PyObject *value = PyStructSequence_GetItem((PyObject*)obj, i); assert(value != NULL); PyObject *repr = PyObject_Repr(value); if (repr == NULL) { From 2ac3eec103cf450aaaebeb932e51155d2e7fb37b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 04:26:52 +0200 Subject: [PATCH 165/446] gh-101634: regrtest reports decoding error as failed test (#106169) When running the Python test suite with -jN option, if a worker stdout cannot be decoded from the locale encoding report a failed testn so the exitcode is non-zero. --- Lib/test/libregrtest/runtest_mp.py | 12 ++++++- Lib/test/test_regrtest.py | 36 +++++++++++++++++++ ...-06-28-02-51-08.gh-issue-101634.Rayczr.rst | 3 ++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py index a12fcb46e0fd0b..62e6c6df36518c 100644 --- a/Lib/test/libregrtest/runtest_mp.py +++ b/Lib/test/libregrtest/runtest_mp.py @@ -277,6 +277,7 @@ def _runtest(self, test_name: str) -> MultiprocessResult: encoding = locale.getencoding() else: encoding = sys.stdout.encoding + # gh-94026: Write stdout+stderr to a tempfile as workaround for # non-blocking pipes on Emscripten with NodeJS. with tempfile.TemporaryFile('w+', encoding=encoding) as stdout_fh: @@ -298,7 +299,14 @@ def _runtest(self, test_name: str) -> MultiprocessResult: retcode = self._run_process(test_name, None, stdout_fh) tmp_files = () stdout_fh.seek(0) - stdout = stdout_fh.read().strip() + + try: + stdout = stdout_fh.read().strip() + except Exception as exc: + # gh-101634: Catch UnicodeDecodeError if stdout cannot be + # decoded from encoding + err_msg = f"Cannot read process stdout: {exc}" + return self.mp_result_error(ChildError(test_name), '', err_msg) if retcode is None: return self.mp_result_error(Timeout(test_name), stdout) @@ -481,6 +489,8 @@ def _process_result(self, item: QueueOutput) -> bool: # Thread got an exception format_exc = item[1] print_warning(f"regrtest worker thread failed: {format_exc}") + result = ChildError("") + self.regrtest.accumulate_result(result) return True self.test_index += 1 diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index ac49fbae847726..806b932a164df8 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -7,6 +7,7 @@ import contextlib import glob import io +import locale import os.path import platform import re @@ -1551,6 +1552,41 @@ def test_leak_tmp_file(self): f"files (1): mytmpfile", output) + def test_mp_decode_error(self): + # gh-101634: If a worker stdout cannot be decoded, report a failed test + # and a non-zero exit code. + if sys.platform == 'win32': + encoding = locale.getencoding() + else: + encoding = sys.stdout.encoding + if encoding is None: + encoding = sys.__stdout__.encoding + if encoding is None: + self.skipTest(f"cannot get regrtest worker encoding") + + nonascii = b"byte:\xa0\xa9\xff\n" + try: + nonascii.decode(encoding) + except UnicodeDecodeError: + pass + else: + self.skipTest(f"{encoding} can decode non-ASCII bytes {nonascii!a}") + + code = textwrap.dedent(fr""" + import sys + # bytes which cannot be decoded from UTF-8 + nonascii = {nonascii!a} + sys.stdout.buffer.write(nonascii) + sys.stdout.buffer.flush() + """) + testname = self.create_test(code=code) + + output = self.run_tests("--fail-env-changed", "-v", "-j1", testname, + exitcode=EXITCODE_BAD_TEST) + self.check_executed_tests(output, [testname], + failed=[testname], + randomize=True) + class TestUtils(unittest.TestCase): def test_format_duration(self): diff --git a/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst new file mode 100644 index 00000000000000..6fbfc84c19e1b8 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-06-28-02-51-08.gh-issue-101634.Rayczr.rst @@ -0,0 +1,3 @@ +When running the Python test suite with ``-jN`` option, if a worker stdout +cannot be decoded from the locale encoding report a failed testn so the +exitcode is non-zero. Patch by Victor Stinner. From adaacf26d3c407e311b453c71abc40672ee549df Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 04:41:21 +0200 Subject: [PATCH 166/446] GH-104584: Fix test_capi.test_counter_optimizer() when run twice (#106171) test_counter_optimizer() and test_long_loop() of test_capi now create a new function at each call. Otherwise, the optimizer counters are not the expected values when the test is run more than once. --- Lib/test/test_capi/test_misc.py | 39 ++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index f2aa2a07783eec..5ee712323d219a 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2372,10 +2372,14 @@ def test_get_set_optimizer(self): self.assertEqual(_testinternalcapi.get_optimizer(), None) def test_counter_optimizer(self): - - def loop(): - for _ in range(1000): - pass + # Generate a new function at each call + ns = {} + exec(textwrap.dedent(""" + def loop(): + for _ in range(1000): + pass + """), ns, ns) + loop = ns['loop'] for repeat in range(5): opt = _testinternalcapi.get_counter_optimizer() @@ -2388,18 +2392,23 @@ def loop(): def test_long_loop(self): "Check that we aren't confused by EXTENDED_ARG" - def nop(): - pass + # Generate a new function at each call + ns = {} + exec(textwrap.dedent(""" + def nop(): + pass - def long_loop(): - for _ in range(10): - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); - nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + def long_loop(): + for _ in range(10): + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); + """), ns, ns) + long_loop = ns['long_loop'] opt = _testinternalcapi.get_counter_optimizer() with self.temporary_optimizer(opt): From 1f74b9e933d546a015e8497e3b8728357196acc8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 28 Jun 2023 04:50:51 +0200 Subject: [PATCH 167/446] Fix c-analyzer for GCC: ignore LANG env var (#106173) The c-analyzer doesn't support GCC localized messages, so just unset the LANG environment variable. --- Tools/c-analyzer/c_parser/preprocessor/common.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index dbe1edeef38527..06f8f4da62b224 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -1,6 +1,7 @@ import contextlib import distutils.ccompiler import logging +import os import shlex import subprocess import sys @@ -40,7 +41,12 @@ def run_cmd(argv, *, kw.pop('kwargs') kwargs.update(kw) - proc = subprocess.run(argv, **kwargs) + # Remove LANG environment variable: the C parser doesn't support GCC + # localized messages + env = dict(os.environ) + env.pop('LANG', None) + + proc = subprocess.run(argv, env=env, **kwargs) return proc.stdout From 541a10f9ed193a79aeea5e244bca6f6485d0689f Mon Sep 17 00:00:00 2001 From: lightdrk <108566237+lightdrk@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:51:38 +0530 Subject: [PATCH 168/446] Refer to `TimeoutError` instead of `asyncio.TimeoutError` in `asyncio-task.rst` (#106136) Co-authored-by: Hugo van Kemenade --- Doc/library/asyncio-task.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 3618bcb6d7c6b5..0651ff7213e527 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -654,16 +654,16 @@ Timeouts If ``long_running_task`` takes more than 10 seconds to complete, the context manager will cancel the current task and handle the resulting :exc:`asyncio.CancelledError` internally, transforming it - into an :exc:`asyncio.TimeoutError` which can be caught and handled. + into a :exc:`TimeoutError` which can be caught and handled. .. note:: The :func:`asyncio.timeout` context manager is what transforms - the :exc:`asyncio.CancelledError` into an :exc:`asyncio.TimeoutError`, - which means the :exc:`asyncio.TimeoutError` can only be caught + the :exc:`asyncio.CancelledError` into a :exc:`TimeoutError`, + which means the :exc:`TimeoutError` can only be caught *outside* of the context manager. - Example of catching :exc:`asyncio.TimeoutError`:: + Example of catching :exc:`TimeoutError`:: async def main(): try: From a3dd8cce58fe2b27eea4eed572d086dc8a7e1bb8 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 28 Jun 2023 16:50:36 +0900 Subject: [PATCH 169/446] gh-106162: fix test_array modifies warning filter (#106181) --- Lib/test/test_array.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index f6bf9e6c5ea871..bec3766b87b202 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -100,6 +100,7 @@ def test_empty(self): class ArrayReconstructorTest(unittest.TestCase): def setUp(self): + self.enterContext(warnings.catch_warnings()) warnings.filterwarnings( "ignore", message="The 'u' type code is deprecated and " From 6b52a581c151914e59c8c367a03bc7309713a73b Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Wed, 28 Jun 2023 11:38:15 +0100 Subject: [PATCH 170/446] gh-105993: Add possible `None` return type to `asyncio.EventLoop.start_tls` docs (#105995) --- Doc/library/asyncio-eventloop.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 8d0022cc66daac..38f2e2f510c176 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -895,6 +895,9 @@ TLS Upgrade object only because the coder caches *protocol*-side data and sporadically exchanges extra TLS session packets with *transport*. + In some situations (e.g. when the passed transport is already closing) this + may return ``None``. + Parameters: * *transport* and *protocol* instances that methods like From bbf722dcd39c66418e45991dcf1cdf140c2ce20e Mon Sep 17 00:00:00 2001 From: F3eQnxN3RriK Date: Wed, 28 Jun 2023 19:43:11 +0900 Subject: [PATCH 171/446] gh-101100: Fix reference to asynchronous methods (#106172) --- Doc/glossary.rst | 18 +++++++++--------- Doc/library/exceptions.rst | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 8c493f823a6fae..931360370d084c 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -83,8 +83,8 @@ Glossary asynchronous context manager An object which controls the environment seen in an - :keyword:`async with` statement by defining :meth:`__aenter__` and - :meth:`__aexit__` methods. Introduced by :pep:`492`. + :keyword:`async with` statement by defining :meth:`~object.__aenter__` and + :meth:`~object.__aexit__` methods. Introduced by :pep:`492`. asynchronous generator A function which returns an :term:`asynchronous generator iterator`. It @@ -104,26 +104,26 @@ Glossary An object created by a :term:`asynchronous generator` function. This is an :term:`asynchronous iterator` which when called using the - :meth:`__anext__` method returns an awaitable object which will execute + :meth:`~object.__anext__` method returns an awaitable object which will execute the body of the asynchronous generator function until the next :keyword:`yield` expression. Each :keyword:`yield` temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements). When the *asynchronous generator iterator* effectively - resumes with another awaitable returned by :meth:`__anext__`, it + resumes with another awaitable returned by :meth:`~object.__anext__`, it picks up where it left off. See :pep:`492` and :pep:`525`. asynchronous iterable An object, that can be used in an :keyword:`async for` statement. Must return an :term:`asynchronous iterator` from its - :meth:`__aiter__` method. Introduced by :pep:`492`. + :meth:`~object.__aiter__` method. Introduced by :pep:`492`. asynchronous iterator - An object that implements the :meth:`__aiter__` and :meth:`__anext__` - methods. ``__anext__`` must return an :term:`awaitable` object. + An object that implements the :meth:`~object.__aiter__` and :meth:`~object.__anext__` + methods. :meth:`~object.__anext__` must return an :term:`awaitable` object. :keyword:`async for` resolves the awaitables returned by an asynchronous - iterator's :meth:`__anext__` method until it raises a + iterator's :meth:`~object.__anext__` method until it raises a :exc:`StopAsyncIteration` exception. Introduced by :pep:`492`. attribute @@ -140,7 +140,7 @@ Glossary awaitable An object that can be used in an :keyword:`await` expression. Can be - a :term:`coroutine` or an object with an :meth:`__await__` method. + a :term:`coroutine` or an object with an :meth:`~object.__await__` method. See also :pep:`492`. BDFL diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 8e574b8334e445..9e1335436ee87f 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -450,7 +450,7 @@ The following exceptions are the exceptions that are usually raised. .. exception:: StopAsyncIteration - Must be raised by :meth:`__anext__` method of an + Must be raised by :meth:`~object.__anext__` method of an :term:`asynchronous iterator` object to stop the iteration. .. versionadded:: 3.5 From 6c60684bf5d34fae27a2f6a142ff794b38cefe1b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 28 Jun 2023 13:11:32 +0200 Subject: [PATCH 172/446] gh-106118: Add O_CLOEXEC preprocessor guard (#106120) --- .../Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst | 2 ++ Python/sysmodule.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst diff --git a/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst b/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst new file mode 100644 index 00000000000000..f93cae5d03b539 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-06-26-21-56-29.gh-issue-106118.0cCfhl.rst @@ -0,0 +1,2 @@ +Fix compilation for platforms without :data:`!O_CLOEXEC`. The issue was +introduced with Python 3.12b1 in :gh:`103295`. Patch by Erlend Aasland. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 3284e14e7742db..0cd8974d197133 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2277,7 +2277,10 @@ PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) { char filename[100]; pid_t pid = getpid(); // Use nofollow flag to prevent symlink attacks. - int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW | O_CLOEXEC; + int flags = O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW; +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map", (intmax_t)pid); int fd = open(filename, flags, 0600); From d830c4a944bcdcc8fe729a60f438fc762965eec1 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 28 Jun 2023 14:55:41 +0300 Subject: [PATCH 173/446] gh-106200: Remove unused imports (#106201) --- Lib/poplib.py | 1 - Lib/test/test_capi/test_misc.py | 2 -- Lib/test/test_tokenize.py | 1 - Tools/cases_generator/lexer.py | 1 - 4 files changed, 5 deletions(-) diff --git a/Lib/poplib.py b/Lib/poplib.py index 9a5ef03c983103..1a1629d175b6d9 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -451,7 +451,6 @@ def stls(self, context=None): __all__.append("POP3_SSL") if __name__ == "__main__": - import sys a = POP3(sys.argv[1]) print(a.getwelcome()) a.user(sys.argv[2]) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 5ee712323d219a..9e825a343eb318 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1823,7 +1823,6 @@ def test_configured_settings(self): 1-to-1 with the new interpreter's settings. This test verifies that they match. """ - import json OBMALLOC = 1<<5 EXTENSIONS = 1<<8 @@ -1902,7 +1901,6 @@ def test_overridden_setting_extensions_subinterp_check(self): This verifies that the override works but does not modify the underlying setting. """ - import json OBMALLOC = 1<<5 EXTENSIONS = 1<<8 diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py index 97c4884f6e33b8..d1552d8a20808f 100644 --- a/Lib/test/test_tokenize.py +++ b/Lib/test/test_tokenize.py @@ -6,7 +6,6 @@ from textwrap import dedent from unittest import TestCase, mock from test import support -from test.support import os_helper from test.test_grammar import (VALID_UNDERSCORE_LITERALS, INVALID_UNDERSCORE_LITERALS) from test.support import os_helper diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py index aa8f1bccf5d968..fe9c05ede5aa47 100644 --- a/Tools/cases_generator/lexer.py +++ b/Tools/cases_generator/lexer.py @@ -3,7 +3,6 @@ # https://gist.github.com/markshannon/db7ab649440b5af765451bb77c7dba34 import re -import sys from dataclasses import dataclass def choice(*opts): From 18f51f91e24402a24a0daa53fcbc81a5a2e9af94 Mon Sep 17 00:00:00 2001 From: F3eQnxN3RriK Date: Wed, 28 Jun 2023 21:30:26 +0900 Subject: [PATCH 174/446] gh-101100: Fix reference to `parse_args` in `optparse.rst` (#105265) --- Doc/library/optparse.rst | 51 +++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 5c02d8bc8835bf..0cff3817452364 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -42,8 +42,8 @@ on the command-line, for example:: --file=outfile -q As it parses the command line, :mod:`optparse` sets attributes of the -``options`` object returned by :meth:`parse_args` based on user-supplied -command-line values. When :meth:`parse_args` returns from parsing this command +``options`` object returned by :meth:`~OptionParser.parse_args` based on user-supplied +command-line values. When :meth:`~OptionParser.parse_args` returns from parsing this command line, ``options.filename`` will be ``"outfile"`` and ``options.verbose`` will be ``False``. :mod:`optparse` supports both long and short options, allows short options to be merged together, and allows options to be associated with their @@ -285,10 +285,10 @@ program's command line:: (options, args) = parser.parse_args() -(If you like, you can pass a custom argument list to :meth:`parse_args`, but +(If you like, you can pass a custom argument list to :meth:`~OptionParser.parse_args`, but that's rarely necessary: by default it uses ``sys.argv[1:]``.) -:meth:`parse_args` returns two values: +:meth:`~OptionParser.parse_args` returns two values: * ``options``, an object containing values for all of your options---e.g. if ``--file`` takes a single string argument, then ``options.file`` will be the @@ -339,7 +339,7 @@ Now let's make up a fake command line and ask :mod:`optparse` to parse it:: When :mod:`optparse` sees the option string ``-f``, it consumes the next argument, ``foo.txt``, and stores it in ``options.filename``. So, after this -call to :meth:`parse_args`, ``options.filename`` is ``"foo.txt"``. +call to :meth:`~OptionParser.parse_args`, ``options.filename`` is ``"foo.txt"``. Some other option types supported by :mod:`optparse` are ``int`` and ``float``. Here's an option that expects an integer argument:: @@ -453,7 +453,8 @@ Again, the default value for ``verbose`` will be ``True``: the last default value supplied for any particular destination is the one that counts. A clearer way to specify default values is the :meth:`set_defaults` method of -OptionParser, which you can call at any time before calling :meth:`parse_args`:: +OptionParser, which you can call at any time before calling +:meth:`~OptionParser.parse_args`:: parser.set_defaults(verbose=True) parser.add_option(...) @@ -1338,35 +1339,37 @@ Parsing arguments ^^^^^^^^^^^^^^^^^ The whole point of creating and populating an OptionParser is to call its -:meth:`parse_args` method:: +:meth:`~OptionParser.parse_args` method. - (options, args) = parser.parse_args(args=None, values=None) +.. method:: OptionParser.parse_args(args=None, values=None) -where the input parameters are + Parse the command-line options found in *args*. -``args`` - the list of arguments to process (default: ``sys.argv[1:]``) + The input parameters are -``values`` - an :class:`optparse.Values` object to store option arguments in (default: a - new instance of :class:`Values`) -- if you give an existing object, the - option defaults will not be initialized on it + ``args`` + the list of arguments to process (default: ``sys.argv[1:]``) -and the return values are + ``values`` + an :class:`Values` object to store option arguments in (default: a + new instance of :class:`Values`) -- if you give an existing object, the + option defaults will not be initialized on it -``options`` - the same object that was passed in as ``values``, or the optparse.Values - instance created by :mod:`optparse` + and the return value is a pair ``(options, args)`` where -``args`` - the leftover positional arguments after all options have been processed + ``options`` + the same object that was passed in as *values*, or the ``optparse.Values`` + instance created by :mod:`optparse` + + ``args`` + the leftover positional arguments after all options have been processed The most common usage is to supply neither keyword argument. If you supply ``values``, it will be modified with repeated :func:`setattr` calls (roughly one for every option argument stored to an option destination) and returned by -:meth:`parse_args`. +:meth:`~OptionParser.parse_args`. -If :meth:`parse_args` encounters any errors in the argument list, it calls the +If :meth:`~OptionParser.parse_args` encounters any errors in the argument list, it calls the OptionParser's :meth:`error` method with an appropriate end-user error message. This ultimately terminates your process with an exit status of 2 (the traditional Unix exit status for command-line errors). @@ -1661,7 +1664,7 @@ where the current list of leftover arguments, ie. arguments that have been consumed but are neither options nor option arguments. Feel free to modify ``parser.largs``, e.g. by adding more arguments to it. (This list will - become ``args``, the second return value of :meth:`parse_args`.) + become ``args``, the second return value of :meth:`~OptionParser.parse_args`.) ``parser.rargs`` the current list of remaining arguments, ie. with ``opt_str`` and From c283a0cff5603540f06d9017e484b3602cc62e7c Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 28 Jun 2023 17:43:41 +0300 Subject: [PATCH 175/446] gh-106197: Deduplicate tests in `test_buffer` (#106198) --- Lib/test/test_buffer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 8d6902e004689b..b679d2e8a01f92 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4722,7 +4722,7 @@ def __buffer__(self, flags): with self.assertRaises(ValueError): c.buffer.tobytes() - def test_multiple_inheritance_buffer_last(self): + def test_multiple_inheritance_buffer_last_raising(self): class A: def __buffer__(self, flags): raise RuntimeError("should not be called") From 11731434df2d7d29b4260e5ad65b993cea775c36 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 28 Jun 2023 11:28:07 -0700 Subject: [PATCH 176/446] gh-104584: Emit macro expansions to opcode_metadata.h (#106163) This produces longer traces (superblocks?). Also improved debug output (uop names are now printed instead of numeric opcodes). This would be simpler if the numeric opcode values were generated by generate_cases.py, but that's another project. Refactored some code in generate_cases.py so the essential algorithm for cache effects is only run once. (Deciding which effects are used and what the total cache size is, regardless of what's used.) --- Python/ceval.c | 6 +- Python/opcode_metadata.h | 32 ++++ Python/optimizer.c | 8 +- Tools/cases_generator/generate_cases.py | 185 +++++++++++++++--------- 4 files changed, 153 insertions(+), 78 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index e19860d04a7914..65b6f2481665de 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2817,10 +2817,10 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject oparg = (int)operand; #ifdef LLTRACE if (lltrace >= 3) { - const char *opname = opcode < 256 ? _PyOpcode_OpName[opcode] : ""; + const char *opname = opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]; int stack_level = (int)(stack_pointer - _PyFrame_Stackbase(frame)); - fprintf(stderr, " uop %s %d, operand %" PRIu64 ", stack_level %d\n", - opname, opcode, operand, stack_level); + fprintf(stderr, " uop %s, operand %" PRIu64 ", stack_level %d\n", + opname, operand, stack_level); } #endif pc++; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 4e31a5e69614bb..cfdc09294e9dee 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -913,6 +913,9 @@ struct opcode_macro_expansion { #ifndef NEED_OPCODE_METADATA extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; +#ifdef Py_DEBUG +extern const char * const _PyOpcode_uop_name[512]; +#endif #else const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [NOP] = { true, INSTR_FMT_IX, 0 }, @@ -1131,10 +1134,18 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [STORE_FAST] = { .nuops = 1, .uops = { { STORE_FAST, 0, 0 } } }, [POP_TOP] = { .nuops = 1, .uops = { { POP_TOP, 0, 0 } } }, [PUSH_NULL] = { .nuops = 1, .uops = { { PUSH_NULL, 0, 0 } } }, + [END_FOR] = { .nuops = 2, .uops = { { POP_TOP, 0, 0 }, { POP_TOP, 0, 0 } } }, [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, [UNARY_INVERT] = { .nuops = 1, .uops = { { UNARY_INVERT, 0, 0 } } }, + [BINARY_OP_MULTIPLY_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_MULTIPLY_INT, 0, 0 } } }, + [BINARY_OP_ADD_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_ADD_INT, 0, 0 } } }, + [BINARY_OP_SUBTRACT_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_SUBTRACT_INT, 0, 0 } } }, + [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, 0, 0 } } }, + [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, + [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, + [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, @@ -1162,6 +1173,9 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [DELETE_ATTR] = { .nuops = 1, .uops = { { DELETE_ATTR, 0, 0 } } }, [STORE_GLOBAL] = { .nuops = 1, .uops = { { STORE_GLOBAL, 0, 0 } } }, [DELETE_GLOBAL] = { .nuops = 1, .uops = { { DELETE_GLOBAL, 0, 0 } } }, + [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, + [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, + [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, [LOAD_DEREF] = { .nuops = 1, .uops = { { LOAD_DEREF, 0, 0 } } }, @@ -1207,4 +1221,22 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; +#ifdef Py_DEBUG +const char * const _PyOpcode_uop_name[512] = { + [300] = "EXIT_TRACE", + [301] = "SET_IP", + [302] = "_GUARD_BOTH_INT", + [303] = "_BINARY_OP_MULTIPLY_INT", + [304] = "_BINARY_OP_ADD_INT", + [305] = "_BINARY_OP_SUBTRACT_INT", + [306] = "_GUARD_BOTH_FLOAT", + [307] = "_BINARY_OP_MULTIPLY_FLOAT", + [308] = "_BINARY_OP_ADD_FLOAT", + [309] = "_BINARY_OP_SUBTRACT_FLOAT", + [310] = "_GUARD_BOTH_UNICODE", + [311] = "_BINARY_OP_ADD_UNICODE", + [312] = "_LOAD_LOCALS", + [313] = "_LOAD_FROM_DICT_OR_GLOBALS", +}; +#endif #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 0a6cc5c92f04f5..9d77ab4ff879bb 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -325,8 +325,8 @@ translate_bytecode_to_trace( } #define ADD_TO_TRACE(OPCODE, OPERAND) \ if (lltrace >= 2) { \ - const char *opname = (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : ""; \ - fprintf(stderr, " ADD_TO_TRACE(%s %d, %" PRIu64 ")\n", opname, (OPCODE), (uint64_t)(OPERAND)); \ + const char *opname = (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)]; \ + fprintf(stderr, " ADD_TO_TRACE(%s, %" PRIu64 ")\n", opname, (uint64_t)(OPERAND)); \ } \ trace[trace_length].opcode = (OPCODE); \ trace[trace_length].operand = (OPERAND); \ @@ -474,6 +474,8 @@ PyUnstable_Optimizer_NewUOpOptimizer(void) } opt->optimize = uop_optimize; opt->resume_threshold = UINT16_MAX; - opt->backedge_threshold = 0; + // Need at least 3 iterations to settle specializations. + // A few lower bits of the counter are reserved for other flags. + opt->backedge_threshold = 3 << OPTIMIZER_BITS_IN_COUNTER; return (PyObject *)opt; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index d66b28139e43fb..7c99e3b929b463 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -300,6 +300,13 @@ def emit_macros(cls, out: Formatter): f"(_PyOpcode_opcode_metadata[(OP)].flags & ({name}))") +@dataclasses.dataclass +class ActiveCacheEffect: + """Wraps a CacheEffect that is actually used, in context.""" + effect: parser.CacheEffect + offset: int + + FORBIDDEN_NAMES_IN_UOPS = ( "resume_with_error", # Proxy for "goto", which isn't an IDENTIFIER "unbound_local_error", @@ -344,6 +351,7 @@ class Instruction: unmoved_names: frozenset[str] instr_fmt: str instr_flags: InstructionFlags + active_caches: list[ActiveCacheEffect] # Set later family: parser.Family | None = None @@ -375,15 +383,19 @@ def __init__(self, inst: parser.InstDef): self.instr_flags = InstructionFlags.fromInstruction(inst) + self.active_caches = [] + offset = 0 + for effect in self.cache_effects: + if effect.name != UNUSED: + self.active_caches.append(ActiveCacheEffect(effect, offset)) + offset += effect.size + if self.instr_flags.HAS_ARG_FLAG: fmt = "IB" else: fmt = "IX" - cache = "C" - for ce in self.cache_effects: - for _ in range(ce.size): - fmt += cache - cache = "0" + if offset: + fmt += "C" + "0"*(offset-1) self.instr_fmt = fmt def is_viable_uop(self) -> bool: @@ -392,18 +404,11 @@ def is_viable_uop(self) -> bool: return False if self.instr_flags.HAS_ARG_FLAG: # If the instruction uses oparg, it cannot use any caches - for c in self.cache_effects: - if c.name != UNUSED: - return False + if self.active_caches: + return False else: # If it doesn't use oparg, it can have one cache entry - caches: list[parser.CacheEffect] = [] - cache_offset = 0 - for c in self.cache_effects: - if c.name != UNUSED: - caches.append(c) - cache_offset += c.size - if len(caches) > 1: + if len(self.active_caches) > 1: return False for forbidden in FORBIDDEN_NAMES_IN_UOPS: # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions @@ -458,7 +463,7 @@ def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None: # out.emit(f"next_instr += OPSIZE({self.inst.name}) - 1;") - self.write_body(out, 0, tier=tier) + self.write_body(out, 0, self.active_caches, tier=tier) # Skip the rest if the block always exits if self.always_exits: @@ -492,33 +497,30 @@ def write_body( self, out: Formatter, dedent: int, - cache_adjust: int = 0, + active_caches: list[ActiveCacheEffect], tier: Tiers = TIER_ONE, ) -> None: """Write the instruction body.""" # Write cache effect variable declarations and initializations - cache_offset = cache_adjust - for ceffect in self.cache_effects: - if ceffect.name != UNUSED: - bits = ceffect.size * BITS_PER_CODE_UNIT - if bits == 64: - # NOTE: We assume that 64-bit data in the cache - # is always an object pointer. - # If this becomes false, we need a way to specify - # syntactically what type the cache data is. - typ = "PyObject *" - func = "read_obj" - else: - typ = f"uint{bits}_t " - func = f"read_u{bits}" - if tier == TIER_ONE: - out.emit( - f"{typ}{ceffect.name} = {func}(&next_instr[{cache_offset}].cache);" - ) - else: - out.emit(f"{typ}{ceffect.name} = operand;") - cache_offset += ceffect.size - assert cache_offset == self.cache_offset + cache_adjust + for active in active_caches: + ceffect = active.effect + bits = ceffect.size * BITS_PER_CODE_UNIT + if bits == 64: + # NOTE: We assume that 64-bit data in the cache + # is always an object pointer. + # If this becomes false, we need a way to specify + # syntactically what type the cache data is. + typ = "PyObject *" + func = "read_obj" + else: + typ = f"uint{bits}_t " + func = f"read_u{bits}" + if tier == TIER_ONE: + out.emit( + f"{typ}{ceffect.name} = {func}(&next_instr[{active.offset}].cache);" + ) + else: + out.emit(f"{typ}{ceffect.name} = operand;") # Write the body, substituting a goto for ERROR_IF() and other stuff assert dedent <= 0 @@ -583,8 +585,9 @@ class Component: instr: Instruction input_mapping: StackEffectMapping output_mapping: StackEffectMapping + active_caches: list[ActiveCacheEffect] - def write_body(self, out: Formatter, cache_adjust: int) -> None: + def write_body(self, out: Formatter) -> None: with out.block(""): input_names = {ieffect.name for _, ieffect in self.input_mapping} for var, ieffect in self.input_mapping: @@ -593,7 +596,7 @@ def write_body(self, out: Formatter, cache_adjust: int) -> None: if oeffect.name not in input_names: out.declare(oeffect, None) - self.instr.write_body(out, dedent=-4, cache_adjust=cache_adjust) + self.instr.write_body(out, -4, self.active_caches) for var, oeffect in self.output_mapping: out.assign(var, oeffect) @@ -611,6 +614,7 @@ class MacroInstruction: instr_flags: InstructionFlags macro: parser.Macro parts: list[Component | parser.CacheEffect] + cache_offset: int predicted: bool = False @@ -873,11 +877,11 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: cache = instr.cache_offset input = len(instr.input_effects) output = len(instr.output_effects) - elif macro := self.macro_instrs.get(name): - cache, input, output = 0, 0, 0 - for part in macro.parts: + elif mac := self.macro_instrs.get(name): + cache = mac.cache_offset + input, output = 0, 0 + for part in mac.parts: if isinstance(part, Component): - cache += part.instr.cache_offset # A component may pop what the previous component pushed, # so we offset the input/output counts by that. delta_i = len(part.instr.input_effects) @@ -885,9 +889,6 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: offset = min(delta_i, output) input += delta_i - offset output += delta_o - offset - else: - assert isinstance(part, parser.CacheEffect), part - cache += part.size else: assert False, f"Unknown instruction {name!r}" return cache, input, output @@ -906,29 +907,25 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: stack, initial_sp = self.stack_analysis(components) sp = initial_sp parts: list[Component | parser.CacheEffect] = [] - format = "IB" flags = InstructionFlags.newEmpty() - cache = "C" + offset = 0 for component in components: match component: case parser.CacheEffect() as ceffect: parts.append(ceffect) - for _ in range(ceffect.size): - format += cache - cache = "0" + offset += ceffect.size case Instruction() as instr: - part, sp = self.analyze_instruction(instr, stack, sp) + part, sp, offset = self.analyze_instruction(instr, stack, sp, offset) parts.append(part) - for ce in instr.cache_effects: - for _ in range(ce.size): - format += cache - cache = "0" flags.add(instr.instr_flags) case _: typing.assert_never(component) final_sp = sp + format = "IB" + if offset: + format += "C" + "0"*(offset-1) return MacroInstruction( - macro.name, stack, initial_sp, final_sp, format, flags, macro, parts + macro.name, stack, initial_sp, final_sp, format, flags, macro, parts, offset ) def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction: @@ -941,8 +938,8 @@ def analyze_pseudo(self, pseudo: parser.Pseudo) -> PseudoInstruction: return PseudoInstruction(pseudo.name, targets, fmts[0], targets[0].instr_flags) def analyze_instruction( - self, instr: Instruction, stack: list[StackEffect], sp: int - ) -> tuple[Component, int]: + self, instr: Instruction, stack: list[StackEffect], sp: int, offset: int + ) -> tuple[Component, int, int]: input_mapping: StackEffectMapping = [] for ieffect in reversed(instr.input_effects): sp -= 1 @@ -951,7 +948,12 @@ def analyze_instruction( for oeffect in instr.output_effects: output_mapping.append((stack[sp], oeffect)) sp += 1 - return Component(instr, input_mapping, output_mapping), sp + active_effects: list[ActiveCacheEffect] = [] + for ceffect in instr.cache_effects: + if ceffect.name != UNUSED: + active_effects.append(ActiveCacheEffect(ceffect, offset)) + offset += ceffect.size + return Component(instr, input_mapping, output_mapping, active_effects), sp, offset def check_macro_components( self, macro: parser.Macro @@ -1030,7 +1032,7 @@ def stack_analysis( def get_stack_effect_info( self, thing: parser.InstDef | parser.Macro | parser.Pseudo - ) -> tuple[AnyInstruction | None, str, str]: + ) -> tuple[AnyInstruction | None, str | None, str | None]: def effect_str(effects: list[StackEffect]) -> str: n_effect, sym_effect = list_effect_size(effects) if sym_effect: @@ -1108,6 +1110,7 @@ def write_stack_effect_functions(self) -> None: continue instr, popped, pushed = self.get_stack_effect_info(thing) if instr is not None: + assert popped is not None and pushed is not None popped_data.append((instr, popped)) pushed_data.append((instr, pushed)) @@ -1182,7 +1185,8 @@ def write_metadata(self) -> None: self.write_pseudo_instrs() - self.write_uop_defines() + self.out.emit("") + self.write_uop_items(lambda name, counter: f"#define {name} {counter}") self.write_stack_effect_functions() @@ -1213,6 +1217,9 @@ def write_metadata(self) -> None: self.out.emit("#ifndef NEED_OPCODE_METADATA") self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") + self.out.emit("#ifdef Py_DEBUG") + self.out.emit("extern const char * const _PyOpcode_uop_name[512];") + self.out.emit("#endif") self.out.emit("#else") self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") @@ -1246,19 +1253,27 @@ def write_metadata(self) -> None: pass case parser.InstDef(name=name): instr = self.instrs[name] + # Since an 'op' is not a bytecode, it has no expansion if instr.kind != "op" and instr.is_viable_uop(): + # Double check there aren't any used cache effects. + # If this fails, see write_macro_expansions(). + assert not instr.active_caches, (instr.name, instr.cache_effects) self.out.emit( f"[{name}] = " f"{{ .nuops = 1, .uops = {{ {{ {name}, 0, 0 }} }} }}," ) case parser.Macro(): - # TODO: emit expansion if all parts are viable uops - pass + self.write_macro_expansions(self.macro_instrs[thing.name]) case parser.Pseudo(): pass case _: typing.assert_never(thing) + self.out.emit("#ifdef Py_DEBUG") + with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): + self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",") + self.out.emit("#endif") + self.out.emit("#endif") with open(self.pymetadata_filename, "w") as f: @@ -1300,13 +1315,12 @@ def write_pseudo_instrs(self) -> None: self.out.emit(f" ((OP) == {op}) || \\") self.out.emit(f" 0") - def write_uop_defines(self) -> None: + def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None: """Write '#define XXX NNN' for each uop""" - self.out.emit("") - counter = 300 + counter = 300 # TODO: Avoid collision with pseudo instructions def add(name: str) -> None: nonlocal counter - self.out.emit(f"#define {name} {counter}") + self.out.emit(make_text(name, counter)) counter += 1 add("EXIT_TRACE") add("SET_IP") @@ -1314,6 +1328,32 @@ def add(name: str) -> None: if instr.kind == "op" and instr.is_viable_uop(): add(instr.name) + def write_macro_expansions(self, mac: MacroInstruction) -> None: + """Write the macro expansions for a macro-instruction.""" + # TODO: Refactor to share code with write_cody(), is_viaible_uop(), etc. + offset = 0 # Cache effect offset + expansions: list[tuple[str, int, int]] = [] # [(name, size, offset), ...] + for part in mac.parts: + if isinstance(part, Component): + # All component instructions must be viable uops + if not part.instr.is_viable_uop(): + print(f"NOTE: Part {part.instr.name} of {mac.name} is not a viable uop") + return + if part.instr.instr_flags.HAS_ARG_FLAG or not part.active_caches: + size, offset = 0, 0 + else: + # If this assert triggers, is_viable_uops() lied + assert len(part.active_caches) == 1, (mac.name, part.instr.name) + cache = part.active_caches[0] + size, offset = cache.effect.size, cache.offset + expansions.append((part.instr.name, size, offset)) + assert len(expansions) > 0, f"Macro {mac.name} has empty expansion?!" + pieces = [f"{{ {name}, {size}, {offset} }}" for name, size, offset in expansions] + self.out.emit( + f"[{mac.name}] = " + f"{{ .nuops = {len(expansions)}, .uops = {{ {', '.join(pieces)} }} }}," + ) + def emit_metadata_entry( self, name: str, fmt: str, flags: InstructionFlags ) -> None: @@ -1379,6 +1419,7 @@ def write_executor_instructions(self) -> None: for thing in self.everything: match thing: case OverriddenInstructionPlaceHolder(): + # TODO: Is this helpful? self.write_overridden_instr_place_holder(thing) case parser.InstDef(): instr = self.instrs[thing.name] @@ -1388,7 +1429,7 @@ def write_executor_instructions(self) -> None: instr.write(self.out, tier=TIER_TWO) self.out.emit("break;") case parser.Macro(): - pass # TODO + pass case parser.Pseudo(): pass case _: @@ -1429,7 +1470,7 @@ def write_macro(self, mac: MacroInstruction) -> None: cache_adjust += size case Component() as comp: last_instr = comp.instr - comp.write_body(self.out, cache_adjust) + comp.write_body(self.out) cache_adjust += comp.instr.cache_offset if cache_adjust: From 4bde89462a95e5962e1467cfc1af5a6094c0c858 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Wed, 28 Jun 2023 13:04:59 -0700 Subject: [PATCH 177/446] GH-106214: Fix `test_opcache` to skip threaded tests on non-threaded platforms (GH-106166) This skips the test added in GH-105953 on threadless builds. --- Lib/test/test_opcache.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 2f6f91ded248bb..564dc4745ae64e 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -2,6 +2,7 @@ import threading import types import unittest +from test.support import threading_helper class TestLoadSuperAttrCache(unittest.TestCase): @@ -484,6 +485,7 @@ def f(x, y): f() +@threading_helper.requires_working_threading() class TestRacesDoNotCrash(unittest.TestCase): # Careful with these. Bigger numbers have a higher chance of catching bugs, # but you can also burn through a *ton* of type/dict/function versions: From 3fb7c608e5764559a718ce8cb81350d7a3df0356 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 28 Jun 2023 23:41:08 +0300 Subject: [PATCH 178/446] gh-106194: Rename duplicated tests in `test_curses` (#106196) --- Lib/test/test_curses.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index 3ab837e4f95681..31bc108e7712ea 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -1364,26 +1364,33 @@ def test_move_left(self): self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_LEFT) self.mock_win.move.assert_called_with(1, 0) + self.mock_win.reset_mock() + + def test_move_right(self): + """Test moving the cursor right.""" + self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() - def test_move_left(self): - """Test moving the cursor left.""" + def test_move_left_and_right(self): + """Test moving the cursor left and then right.""" self.mock_win.reset_mock() + self.textbox.do_command(curses.KEY_LEFT) + self.mock_win.move.assert_called_with(1, 0) self.textbox.do_command(curses.KEY_RIGHT) self.mock_win.move.assert_called_with(1, 2) self.mock_win.reset_mock() def test_move_up(self): - """Test moving the cursor left.""" + """Test moving the cursor up.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_UP) self.mock_win.move.assert_called_with(0, 1) self.mock_win.reset_mock() def test_move_down(self): - """Test moving the cursor left.""" + """Test moving the cursor down.""" self.mock_win.reset_mock() self.textbox.do_command(curses.KEY_DOWN) self.mock_win.move.assert_called_with(2, 1) From 8bf6904b229583033035d91a3800da5604dcaad4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jun 2023 12:22:19 +0300 Subject: [PATCH 179/446] gh-101006: Improve error handling when read marshal data (GH-101007) * EOFError no longer overrides other errors such as MemoryError or OSError at the start of the object. * Raise more relevant error when the NULL object occurs as a code object component. * Minimize an overhead of calling PyErr_Occurred(). --- ...-01-13-11-37-41.gh-issue-101006.fuLvn2.rst | 1 + Python/marshal.c | 132 ++++++++++-------- 2 files changed, 72 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst new file mode 100644 index 00000000000000..c98670d8c4963d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-13-11-37-41.gh-issue-101006.fuLvn2.rst @@ -0,0 +1 @@ +Improve error handling when read :mod:`marshal` data. diff --git a/Python/marshal.c b/Python/marshal.c index 972a13876e626b..7cfc7cc00306f5 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -751,23 +751,28 @@ r_string(Py_ssize_t n, RFILE *p) static int r_byte(RFILE *p) { - int c = EOF; - if (p->ptr != NULL) { - if (p->ptr < p->end) - c = (unsigned char) *p->ptr++; - return c; + if (p->ptr < p->end) { + return (unsigned char) *p->ptr++; + } } - if (!p->readable) { + else if (!p->readable) { assert(p->fp); - c = getc(p->fp); + int c = getc(p->fp); + if (c != EOF) { + return c; + } } else { const char *ptr = r_string(1, p); - if (ptr != NULL) - c = *(const unsigned char *) ptr; + if (ptr != NULL) { + return *(const unsigned char *) ptr; + } + return EOF; } - return c; + PyErr_SetString(PyExc_EOFError, + "EOF read where not expected"); + return EOF; } static int @@ -828,10 +833,11 @@ r_PyLong(RFILE *p) digit d; n = r_long(p); - if (PyErr_Occurred()) - return NULL; if (n == 0) return (PyObject *)_PyLong_New(0); + if (n == -1 && PyErr_Occurred()) { + return NULL; + } if (n < -SIZE32_MAX || n > SIZE32_MAX) { PyErr_SetString(PyExc_ValueError, "bad marshal data (long size out of range)"); @@ -850,10 +856,6 @@ r_PyLong(RFILE *p) d = 0; for (j=0; j < PyLong_MARSHAL_RATIO; j++) { md = r_short(p); - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; d += (digit)md << j*PyLong_MARSHAL_SHIFT; @@ -864,10 +866,6 @@ r_PyLong(RFILE *p) d = 0; for (j=0; j < shorts_in_top_digit; j++) { md = r_short(p); - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } if (md < 0 || md > PyLong_MARSHAL_BASE) goto bad_digit; /* topmost marshal digit should be nonzero */ @@ -879,18 +877,17 @@ r_PyLong(RFILE *p) } d += (digit)md << j*PyLong_MARSHAL_SHIFT; } - if (PyErr_Occurred()) { - Py_DECREF(ob); - return NULL; - } + assert(!PyErr_Occurred()); /* top digit should be nonzero, else the resulting PyLong won't be normalized */ ob->long_value.ob_digit[size-1] = d; return (PyObject *)ob; bad_digit: Py_DECREF(ob); - PyErr_SetString(PyExc_ValueError, - "bad marshal data (digit out of range in long)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (digit out of range in long)"); + } return NULL; } @@ -913,8 +910,6 @@ r_float_str(RFILE *p) const char *ptr; n = r_byte(p); if (n == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); return -1; } ptr = r_string(n, p); @@ -992,8 +987,10 @@ r_object(RFILE *p) PyObject *retval = NULL; if (code == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); + if (PyErr_ExceptionMatches(PyExc_EOFError)) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + } return NULL; } @@ -1040,7 +1037,10 @@ r_object(RFILE *p) case TYPE_INT: n = r_long(p); - retval = PyErr_Occurred() ? NULL : PyLong_FromLong(n); + if (n == -1 && PyErr_Occurred()) { + break; + } + retval = PyLong_FromLong(n); R_REF(retval); break; @@ -1106,10 +1106,11 @@ r_object(RFILE *p) { const char *ptr; n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (bytes object size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (bytes object size out of range)"); + } break; } v = PyBytes_FromStringAndSize((char *)NULL, n); @@ -1131,10 +1132,11 @@ r_object(RFILE *p) /* fall through */ case TYPE_ASCII: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (string size out of range)"); + } break; } goto _read_ascii; @@ -1145,8 +1147,6 @@ r_object(RFILE *p) case TYPE_SHORT_ASCII: n = r_byte(p); if (n == EOF) { - PyErr_SetString(PyExc_EOFError, - "EOF read where object expected"); break; } _read_ascii: @@ -1173,10 +1173,11 @@ r_object(RFILE *p) const char *buffer; n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (string size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (string size out of range)"); + } break; } if (n != 0) { @@ -1198,16 +1199,18 @@ r_object(RFILE *p) } case TYPE_SMALL_TUPLE: - n = (unsigned char) r_byte(p); - if (PyErr_Occurred()) + n = r_byte(p); + if (n == EOF) { break; + } goto _read_tuple; case TYPE_TUPLE: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (tuple size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (tuple size out of range)"); + } break; } _read_tuple: @@ -1232,10 +1235,11 @@ r_object(RFILE *p) case TYPE_LIST: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (list size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (list size out of range)"); + } break; } v = PyList_New(n); @@ -1288,10 +1292,11 @@ r_object(RFILE *p) case TYPE_SET: case TYPE_FROZENSET: n = r_long(p); - if (PyErr_Occurred()) - break; if (n < 0 || n > SIZE32_MAX) { - PyErr_SetString(PyExc_ValueError, "bad marshal data (set size out of range)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (set size out of range)"); + } break; } @@ -1368,20 +1373,20 @@ r_object(RFILE *p) /* XXX ignore long->int overflows for now */ argcount = (int)r_long(p); - if (PyErr_Occurred()) + if (argcount == -1 && PyErr_Occurred()) goto code_error; posonlyargcount = (int)r_long(p); - if (PyErr_Occurred()) { + if (posonlyargcount == -1 && PyErr_Occurred()) { goto code_error; } kwonlyargcount = (int)r_long(p); - if (PyErr_Occurred()) + if (kwonlyargcount == -1 && PyErr_Occurred()) goto code_error; stacksize = (int)r_long(p); - if (PyErr_Occurred()) + if (stacksize == -1 && PyErr_Occurred()) goto code_error; flags = (int)r_long(p); - if (PyErr_Occurred()) + if (flags == -1 && PyErr_Occurred()) goto code_error; code = r_object(p); if (code == NULL) @@ -1454,6 +1459,10 @@ r_object(RFILE *p) v = r_ref_insert(v, idx, flag, p); code_error: + if (v == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "NULL object in marshal data for code object"); + } Py_XDECREF(code); Py_XDECREF(consts); Py_XDECREF(names); @@ -1471,9 +1480,10 @@ r_object(RFILE *p) case TYPE_REF: n = r_long(p); if (n < 0 || n >= PyList_GET_SIZE(p->refs)) { - if (n == -1 && PyErr_Occurred()) - break; - PyErr_SetString(PyExc_ValueError, "bad marshal data (invalid reference)"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data (invalid reference)"); + } break; } v = PyList_GET_ITEM(p->refs, n); From 08c08d21b03d949452a77d9ed5e3cf48d6b9804d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jun 2023 12:31:08 +0300 Subject: [PATCH 180/446] gh-106033: Get rid of PyDict_GetItem in _PyFunction_FromConstructor (GH-106044) --- Objects/funcobject.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 753038600aa858..f43e3a2787b846 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -106,9 +106,14 @@ PyFunction_ClearWatcher(int watcher_id) PyFunctionObject * _PyFunction_FromConstructor(PyFrameConstructor *constr) { + PyObject *module = Py_XNewRef(PyDict_GetItemWithError(constr->fc_globals, &_Py_ID(__name__))); + if (!module && PyErr_Occurred()) { + return NULL; + } PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); if (op == NULL) { + Py_XDECREF(module); return NULL; } op->func_globals = Py_NewRef(constr->fc_globals); @@ -122,10 +127,7 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) op->func_doc = Py_NewRef(Py_None); op->func_dict = NULL; op->func_weakreflist = NULL; - op->func_module = Py_XNewRef(PyDict_GetItem(op->func_globals, &_Py_ID(__name__))); - if (!op->func_module) { - PyErr_Clear(); - } + op->func_module = module; op->func_annotations = NULL; op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; From 0e24499129f3917b199a6d46fa33eeedd2c447fc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jun 2023 12:53:22 +0300 Subject: [PATCH 181/446] gh-89392: Make test_decimal discoverable (GH-106209) --- Lib/test/test_decimal.py | 279 ++++++++++++++++++++------------------- 1 file changed, 146 insertions(+), 133 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 67ccaab40c5edc..749496e3e9455e 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -20,7 +20,7 @@ This test module can be called from command line with one parameter (Arithmetic or Behaviour) to test each part, or without parameter to test both parts. If -you're working through IDLE, you can import this test module and call test_main() +you're working through IDLE, you can import this test module and call test() with the corresponding argument. """ @@ -32,7 +32,7 @@ import unittest import numbers import locale -from test.support import (run_unittest, run_doctest, is_resource_enabled, +from test.support import (is_resource_enabled, requires_IEEE_754, requires_docstrings, requires_legacy_unicode_capi, check_sanitizer) from test.support import (TestFailed, @@ -62,6 +62,7 @@ fractions = {C:cfractions, P:pfractions} sys.modules['decimal'] = orig_sys_decimal +requires_cdecimal = unittest.skipUnless(C, "test requires C version") # Useful Test Constant Signals = { @@ -99,7 +100,7 @@ def assert_signals(cls, context, attr, expected): ] # Tests are built around these assumed context defaults. -# test_main() restores the original context. +# test() restores the original context. ORIGINAL_CONTEXT = { C: C.getcontext().copy() if C else None, P: P.getcontext().copy() @@ -133,7 +134,7 @@ def init(m): EXTRA_FUNCTIONALITY, "test requires regular build") -class IBMTestCases(unittest.TestCase): +class IBMTestCases: """Class which tests the Decimal class against the IBM test cases.""" def setUp(self): @@ -488,14 +489,10 @@ def change_max_exponent(self, exp): def change_clamp(self, clamp): self.context.clamp = clamp -class CIBMTestCases(IBMTestCases): - decimal = C -class PyIBMTestCases(IBMTestCases): - decimal = P # The following classes test the behaviour of Decimal according to PEP 327 -class ExplicitConstructionTest(unittest.TestCase): +class ExplicitConstructionTest: '''Unit tests for Explicit Construction cases of Decimal.''' def test_explicit_empty(self): @@ -838,12 +835,13 @@ def test_unicode_digits(self): for input, expected in test_values.items(): self.assertEqual(str(Decimal(input)), expected) -class CExplicitConstructionTest(ExplicitConstructionTest): +@requires_cdecimal +class CExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase): decimal = C -class PyExplicitConstructionTest(ExplicitConstructionTest): +class PyExplicitConstructionTest(ExplicitConstructionTest, unittest.TestCase): decimal = P -class ImplicitConstructionTest(unittest.TestCase): +class ImplicitConstructionTest: '''Unit tests for Implicit Construction cases of Decimal.''' def test_implicit_from_None(self): @@ -920,12 +918,13 @@ def __ne__(self, other): self.assertEqual(eval('Decimal(10)' + sym + 'E()'), '10' + rop + 'str') -class CImplicitConstructionTest(ImplicitConstructionTest): +@requires_cdecimal +class CImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase): decimal = C -class PyImplicitConstructionTest(ImplicitConstructionTest): +class PyImplicitConstructionTest(ImplicitConstructionTest, unittest.TestCase): decimal = P -class FormatTest(unittest.TestCase): +class FormatTest: '''Unit tests for the format function.''' def test_formatting(self): Decimal = self.decimal.Decimal @@ -1262,12 +1261,13 @@ def __init__(self, a): a = A.from_float(42) self.assertEqual(self.decimal.Decimal, a.a_type) -class CFormatTest(FormatTest): +@requires_cdecimal +class CFormatTest(FormatTest, unittest.TestCase): decimal = C -class PyFormatTest(FormatTest): +class PyFormatTest(FormatTest, unittest.TestCase): decimal = P -class ArithmeticOperatorsTest(unittest.TestCase): +class ArithmeticOperatorsTest: '''Unit tests for all arithmetic operators, binary and unary.''' def test_addition(self): @@ -1523,14 +1523,17 @@ def test_nan_comparisons(self): equality_ops = operator.eq, operator.ne # results when InvalidOperation is not trapped - for x, y in qnan_pairs + snan_pairs: - for op in order_ops + equality_ops: - got = op(x, y) - expected = True if op is operator.ne else False - self.assertIs(expected, got, - "expected {0!r} for operator.{1}({2!r}, {3!r}); " - "got {4!r}".format( - expected, op.__name__, x, y, got)) + with localcontext() as ctx: + ctx.traps[InvalidOperation] = 0 + + for x, y in qnan_pairs + snan_pairs: + for op in order_ops + equality_ops: + got = op(x, y) + expected = True if op is operator.ne else False + self.assertIs(expected, got, + "expected {0!r} for operator.{1}({2!r}, {3!r}); " + "got {4!r}".format( + expected, op.__name__, x, y, got)) # repeat the above, but this time trap the InvalidOperation with localcontext() as ctx: @@ -1562,9 +1565,10 @@ def test_copy_sign(self): self.assertEqual(Decimal(1).copy_sign(-2), d) self.assertRaises(TypeError, Decimal(1).copy_sign, '-2') -class CArithmeticOperatorsTest(ArithmeticOperatorsTest): +@requires_cdecimal +class CArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase): decimal = C -class PyArithmeticOperatorsTest(ArithmeticOperatorsTest): +class PyArithmeticOperatorsTest(ArithmeticOperatorsTest, unittest.TestCase): decimal = P # The following are two functions used to test threading in the next class @@ -1654,7 +1658,7 @@ def thfunc2(cls): @threading_helper.requires_working_threading() -class ThreadingTest(unittest.TestCase): +class ThreadingTest: '''Unit tests for thread local contexts in Decimal.''' # Take care executing this test from IDLE, there's an issue in threading @@ -1699,13 +1703,14 @@ def test_threading(self): DefaultContext.Emin = save_emin -class CThreadingTest(ThreadingTest): +@requires_cdecimal +class CThreadingTest(ThreadingTest, unittest.TestCase): decimal = C -class PyThreadingTest(ThreadingTest): +class PyThreadingTest(ThreadingTest, unittest.TestCase): decimal = P -class UsabilityTest(unittest.TestCase): +class UsabilityTest: '''Unit tests for Usability cases of Decimal.''' def test_comparison_operators(self): @@ -2521,9 +2526,10 @@ def test_conversions_from_int(self): self.assertEqual(Decimal(-12).fma(45, Decimal(67)), Decimal(-12).fma(Decimal(45), Decimal(67))) -class CUsabilityTest(UsabilityTest): +@requires_cdecimal +class CUsabilityTest(UsabilityTest, unittest.TestCase): decimal = C -class PyUsabilityTest(UsabilityTest): +class PyUsabilityTest(UsabilityTest, unittest.TestCase): decimal = P def setUp(self): @@ -2535,7 +2541,7 @@ def tearDown(self): sys.set_int_max_str_digits(self._previous_int_limit) super().tearDown() -class PythonAPItests(unittest.TestCase): +class PythonAPItests: def test_abc(self): Decimal = self.decimal.Decimal @@ -2884,12 +2890,13 @@ def test_exception_hierarchy(self): self.assertTrue(issubclass(decimal.DivisionUndefined, ZeroDivisionError)) self.assertTrue(issubclass(decimal.InvalidContext, InvalidOperation)) -class CPythonAPItests(PythonAPItests): +@requires_cdecimal +class CPythonAPItests(PythonAPItests, unittest.TestCase): decimal = C -class PyPythonAPItests(PythonAPItests): +class PyPythonAPItests(PythonAPItests, unittest.TestCase): decimal = P -class ContextAPItests(unittest.TestCase): +class ContextAPItests: def test_none_args(self): Context = self.decimal.Context @@ -3635,12 +3642,13 @@ def test_to_integral_value(self): self.assertRaises(TypeError, c.to_integral_value, '10') self.assertRaises(TypeError, c.to_integral_value, 10, 'x') -class CContextAPItests(ContextAPItests): +@requires_cdecimal +class CContextAPItests(ContextAPItests, unittest.TestCase): decimal = C -class PyContextAPItests(ContextAPItests): +class PyContextAPItests(ContextAPItests, unittest.TestCase): decimal = P -class ContextWithStatement(unittest.TestCase): +class ContextWithStatement: # Can't do these as docstrings until Python 2.6 # as doctest can't handle __future__ statements @@ -3704,9 +3712,13 @@ def test_localcontext_kwargs(self): def test_local_context_kwargs_does_not_overwrite_existing_argument(self): ctx = self.decimal.getcontext() - ctx.prec = 28 + orig_prec = ctx.prec with self.decimal.localcontext(prec=10) as ctx2: - self.assertEqual(ctx.prec, 28) + self.assertEqual(ctx2.prec, 10) + self.assertEqual(ctx.prec, orig_prec) + with self.decimal.localcontext(prec=20) as ctx2: + self.assertEqual(ctx2.prec, 20) + self.assertEqual(ctx.prec, orig_prec) def test_nested_with_statements(self): # Use a copy of the supplied context in the block @@ -3800,12 +3812,13 @@ def test_with_statements_gc3(self): self.assertEqual(c4.prec, 4) del c4 -class CContextWithStatement(ContextWithStatement): +@requires_cdecimal +class CContextWithStatement(ContextWithStatement, unittest.TestCase): decimal = C -class PyContextWithStatement(ContextWithStatement): +class PyContextWithStatement(ContextWithStatement, unittest.TestCase): decimal = P -class ContextFlags(unittest.TestCase): +class ContextFlags: def test_flags_irrelevant(self): # check that the result (numeric result + flags raised) of an @@ -4072,12 +4085,13 @@ def test_float_operation_default(self): self.assertTrue(context.traps[FloatOperation]) self.assertTrue(context.traps[Inexact]) -class CContextFlags(ContextFlags): +@requires_cdecimal +class CContextFlags(ContextFlags, unittest.TestCase): decimal = C -class PyContextFlags(ContextFlags): +class PyContextFlags(ContextFlags, unittest.TestCase): decimal = P -class SpecialContexts(unittest.TestCase): +class SpecialContexts: """Test the context templates.""" def test_context_templates(self): @@ -4157,12 +4171,13 @@ def test_default_context(self): if ex: raise ex -class CSpecialContexts(SpecialContexts): +@requires_cdecimal +class CSpecialContexts(SpecialContexts, unittest.TestCase): decimal = C -class PySpecialContexts(SpecialContexts): +class PySpecialContexts(SpecialContexts, unittest.TestCase): decimal = P -class ContextInputValidation(unittest.TestCase): +class ContextInputValidation: def test_invalid_context(self): Context = self.decimal.Context @@ -4224,12 +4239,13 @@ def test_invalid_context(self): self.assertRaises(TypeError, Context, flags=(0,1)) self.assertRaises(TypeError, Context, traps=(1,0)) -class CContextInputValidation(ContextInputValidation): +@requires_cdecimal +class CContextInputValidation(ContextInputValidation, unittest.TestCase): decimal = C -class PyContextInputValidation(ContextInputValidation): +class PyContextInputValidation(ContextInputValidation, unittest.TestCase): decimal = P -class ContextSubclassing(unittest.TestCase): +class ContextSubclassing: def test_context_subclassing(self): decimal = self.decimal @@ -4338,12 +4354,14 @@ def __init__(self, prec=None, rounding=None, Emin=None, Emax=None, for signal in OrderedSignals[decimal]: self.assertFalse(c.traps[signal]) -class CContextSubclassing(ContextSubclassing): +@requires_cdecimal +class CContextSubclassing(ContextSubclassing, unittest.TestCase): decimal = C -class PyContextSubclassing(ContextSubclassing): +class PyContextSubclassing(ContextSubclassing, unittest.TestCase): decimal = P @skip_if_extra_functionality +@requires_cdecimal class CheckAttributes(unittest.TestCase): def test_module_attributes(self): @@ -4373,7 +4391,7 @@ def test_decimal_attributes(self): y = [s for s in dir(C.Decimal(9)) if '__' in s or not s.startswith('_')] self.assertEqual(set(x) - set(y), set()) -class Coverage(unittest.TestCase): +class Coverage: def test_adjusted(self): Decimal = self.decimal.Decimal @@ -4630,9 +4648,10 @@ def test_copy(self): y = c.copy_sign(x, 1) self.assertEqual(y, -x) -class CCoverage(Coverage): +@requires_cdecimal +class CCoverage(Coverage, unittest.TestCase): decimal = C -class PyCoverage(Coverage): +class PyCoverage(Coverage, unittest.TestCase): decimal = P def setUp(self): @@ -4885,6 +4904,7 @@ def test_constants(self): self.assertEqual(C.DecTraps, C.DecErrors|C.DecOverflow|C.DecUnderflow) +@requires_cdecimal class CWhitebox(unittest.TestCase): """Whitebox testing for _decimal""" @@ -5663,7 +5683,7 @@ def test_maxcontext_exact_arith(self): @requires_docstrings -@unittest.skipUnless(C, "test requires C version") +@requires_cdecimal class SignatureTest(unittest.TestCase): """Function signatures""" @@ -5799,52 +5819,10 @@ def doit(ty): doit('Context') -all_tests = [ - CExplicitConstructionTest, PyExplicitConstructionTest, - CImplicitConstructionTest, PyImplicitConstructionTest, - CFormatTest, PyFormatTest, - CArithmeticOperatorsTest, PyArithmeticOperatorsTest, - CThreadingTest, PyThreadingTest, - CUsabilityTest, PyUsabilityTest, - CPythonAPItests, PyPythonAPItests, - CContextAPItests, PyContextAPItests, - CContextWithStatement, PyContextWithStatement, - CContextFlags, PyContextFlags, - CSpecialContexts, PySpecialContexts, - CContextInputValidation, PyContextInputValidation, - CContextSubclassing, PyContextSubclassing, - CCoverage, PyCoverage, - CFunctionality, PyFunctionality, - CWhitebox, PyWhitebox, - CIBMTestCases, PyIBMTestCases, -] - -# Delete C tests if _decimal.so is not present. -if not C: - all_tests = all_tests[1::2] -else: - all_tests.insert(0, CheckAttributes) - all_tests.insert(1, SignatureTest) - - -def test_main(arith=None, verbose=None, todo_tests=None, debug=None): - """ Execute the tests. - - Runs all arithmetic tests if arith is True or if the "decimal" resource - is enabled in regrtest.py - """ - - init(C) - init(P) - global TEST_ALL, DEBUG - TEST_ALL = arith if arith is not None else is_resource_enabled('decimal') - DEBUG = debug - - if todo_tests is None: - test_classes = all_tests - else: - test_classes = [CIBMTestCases, PyIBMTestCases] - +def load_tests(loader, tests, pattern): + if TODO_TESTS is not None: + # Run only Arithmetic tests + tests = loader.suiteClass() # Dynamically build custom test definition for each file in the test # directory and add the definitions to the DecimalTest class. This # procedure insures that new files do not get skipped. @@ -5852,34 +5830,69 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None): if '.decTest' not in filename or filename.startswith("."): continue head, tail = filename.split('.') - if todo_tests is not None and head not in todo_tests: + if TODO_TESTS is not None and head not in TODO_TESTS: continue tester = lambda self, f=filename: self.eval_file(directory + f) - setattr(CIBMTestCases, 'test_' + head, tester) - setattr(PyIBMTestCases, 'test_' + head, tester) + setattr(IBMTestCases, 'test_' + head, tester) del filename, head, tail, tester + for prefix, mod in ('C', C), ('Py', P): + if not mod: + continue + test_class = type(prefix + 'IBMTestCases', + (IBMTestCases, unittest.TestCase), + {'decimal': mod}) + tests.addTest(loader.loadTestsFromTestCase(test_class)) + + if TODO_TESTS is None: + from doctest import DocTestSuite, IGNORE_EXCEPTION_DETAIL + for mod in C, P: + if not mod: + continue + def setUp(slf, mod=mod): + sys.modules['decimal'] = mod + def tearDown(slf): + sys.modules['decimal'] = orig_sys_decimal + optionflags = IGNORE_EXCEPTION_DETAIL if mod is C else 0 + sys.modules['decimal'] = mod + tests.addTest(DocTestSuite(mod, setUp=setUp, tearDown=tearDown, + optionflags=optionflags)) + sys.modules['decimal'] = orig_sys_decimal + return tests + +def setUpModule(): + init(C) + init(P) + global TEST_ALL + TEST_ALL = ARITH if ARITH is not None else is_resource_enabled('decimal') + +def tearDownModule(): + if C: C.setcontext(ORIGINAL_CONTEXT[C]) + P.setcontext(ORIGINAL_CONTEXT[P]) + if not C: + warnings.warn('C tests skipped: no module named _decimal.', + UserWarning) + if not orig_sys_decimal is sys.modules['decimal']: + raise TestFailed("Internal error: unbalanced number of changes to " + "sys.modules['decimal'].") + + +ARITH = None +TEST_ALL = True +TODO_TESTS = None +DEBUG = False + +def test(arith=None, verbose=None, todo_tests=None, debug=None): + """ Execute the tests. + Runs all arithmetic tests if arith is True or if the "decimal" resource + is enabled in regrtest.py + """ - try: - run_unittest(*test_classes) - if todo_tests is None: - from doctest import IGNORE_EXCEPTION_DETAIL - savedecimal = sys.modules['decimal'] - if C: - sys.modules['decimal'] = C - run_doctest(C, verbose, optionflags=IGNORE_EXCEPTION_DETAIL) - sys.modules['decimal'] = P - run_doctest(P, verbose) - sys.modules['decimal'] = savedecimal - finally: - if C: C.setcontext(ORIGINAL_CONTEXT[C]) - P.setcontext(ORIGINAL_CONTEXT[P]) - if not C: - warnings.warn('C tests skipped: no module named _decimal.', - UserWarning) - if not orig_sys_decimal is sys.modules['decimal']: - raise TestFailed("Internal error: unbalanced number of changes to " - "sys.modules['decimal'].") + global ARITH, TODO_TESTS, DEBUG + ARITH = arith + TODO_TESTS = todo_tests + DEBUG = debug + unittest.main(__name__, verbosity=2 if verbose else 1, exit=False, argv=[__name__]) if __name__ == '__main__': @@ -5890,8 +5903,8 @@ def test_main(arith=None, verbose=None, todo_tests=None, debug=None): (opt, args) = p.parse_args() if opt.skip: - test_main(arith=False, verbose=True) + test(arith=False, verbose=True) elif args: - test_main(arith=True, verbose=True, todo_tests=args, debug=opt.debug) + test(arith=True, verbose=True, todo_tests=args, debug=opt.debug) else: - test_main(arith=True, verbose=True) + test(arith=True, verbose=True) From fb0d9b9ac1ec3ea13fae8b8ef6a4f0a5a80482b3 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Thu, 29 Jun 2023 18:27:20 +0800 Subject: [PATCH 182/446] gh-106078: Convert `_decimal` types to heap types (#106079) - Establish global state struct - Convert static types to heap types and add them to global state: * PyDecContextManager_Type * PyDecContext_Type * PyDecSignalDictMixin_Type * PyDec_Type - Add to global state: * PyDecSignalDict_Type * DecimalTuple Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Co-authored-by: Erlend E. Aasland --- Lib/test/test_decimal.py | 21 +- Modules/_decimal/_decimal.c | 795 ++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 7 +- 3 files changed, 433 insertions(+), 390 deletions(-) diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 749496e3e9455e..db67f37608f1f2 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -34,7 +34,8 @@ import locale from test.support import (is_resource_enabled, requires_IEEE_754, requires_docstrings, - requires_legacy_unicode_capi, check_sanitizer) + requires_legacy_unicode_capi, check_sanitizer, + check_disallow_instantiation) from test.support import (TestFailed, run_with_locale, cpython_only, darwin_malloc_err_warning, is_emscripten) @@ -5681,6 +5682,24 @@ def test_maxcontext_exact_arith(self): self.assertEqual(Decimal(4) / 2, 2) self.assertEqual(Decimal(400) ** -1, Decimal('0.0025')) + def test_c_immutable_types(self): + SignalDict = type(C.Context().flags) + SignalDictMixin = SignalDict.__bases__[0] + ContextManager = type(C.localcontext()) + types = ( + SignalDictMixin, + ContextManager, + C.Decimal, + C.Context, + ) + for tp in types: + with self.subTest(tp=tp): + with self.assertRaisesRegex(TypeError, "immutable"): + tp.foo = 1 + + def test_c_disallow_instantiation(self): + ContextManager = type(C.localcontext()) + check_disallow_instantiation(self, ContextManager) @requires_docstrings @requires_cdecimal diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 73df3f34829f08..b7cb19515b3002 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,18 @@ #include "docstrings.h" +typedef struct { + PyTypeObject *PyDecContextManager_Type; + PyTypeObject *PyDecContext_Type; + PyTypeObject *PyDecSignalDictMixin_Type; + PyTypeObject *PyDec_Type; + PyTypeObject *PyDecSignalDict_Type; + PyTypeObject *DecimalTuple; +} decimal_state; + +static decimal_state global_state; + +#define GLOBAL_STATE() (&global_state) #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 #error "libmpdec version >= 2.5.0 required" @@ -99,14 +111,10 @@ typedef struct { #undef MPD #undef CTX -static PyTypeObject PyDec_Type; -static PyTypeObject *PyDecSignalDict_Type; -static PyTypeObject PyDecContext_Type; -static PyTypeObject PyDecContextManager_Type; -#define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) -#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) -#define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) -#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type) +#define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type) +#define PyDec_Check(st, v) PyObject_TypeCheck(v, (st)->PyDec_Type) +#define PyDecSignalDict_Check(st, v) Py_IS_TYPE(v, (st)->PyDecSignalDict_Type) +#define PyDecContext_Check(st, v) PyObject_TypeCheck(v, (st)->PyDecContext_Type) #define MPD(v) (&((PyDecObject *)v)->dec) #define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) #define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) @@ -603,6 +611,22 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) return 0; } +static int +signaldict_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +signaldict_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + static PyObject * signaldict_repr(PyObject *self) { @@ -631,10 +655,11 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) { PyObject *res = Py_NotImplemented; - assert(PyDecSignalDict_Check(v)); + decimal_state *state = GLOBAL_STATE(); + assert(PyDecSignalDict_Check(state, v)); if (op == Py_EQ || op == Py_NE) { - if (PyDecSignalDict_Check(w)) { + if (PyDecSignalDict_Check(state, w)) { res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; } else if (PyDict_Check(w)) { @@ -664,58 +689,36 @@ signaldict_copy(PyObject *self, PyObject *args UNUSED) } -static PyMappingMethods signaldict_as_mapping = { - (lenfunc)signaldict_len, /* mp_length */ - (binaryfunc)signaldict_getitem, /* mp_subscript */ - (objobjargproc)signaldict_setitem /* mp_ass_subscript */ -}; - static PyMethodDef signaldict_methods[] = { { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL}, {NULL, NULL} }; -static PyTypeObject PyDecSignalDictMixin_Type = -{ - PyVarObject_HEAD_INIT(0, 0) - "decimal.SignalDictMixin", /* tp_name */ - sizeof(PyDecSignalDictObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) signaldict_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - &signaldict_as_mapping, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - signaldict_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)signaldict_iter, /* tp_iter */ - 0, /* tp_iternext */ - signaldict_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)signaldict_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot signaldict_slots[] = { + {Py_tp_dealloc, signaldict_dealloc}, + {Py_tp_traverse, signaldict_traverse}, + {Py_tp_repr, signaldict_repr}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_richcompare, signaldict_richcompare}, + {Py_tp_iter, signaldict_iter}, + {Py_tp_methods, signaldict_methods}, + {Py_tp_init, signaldict_init}, + + // Mapping protocol + {Py_mp_length, signaldict_len}, + {Py_mp_subscript, signaldict_getitem}, + {Py_mp_ass_subscript, signaldict_setitem}, + {0, NULL}, +}; + +static PyType_Spec signaldict_spec = { + .name = "decimal.SignalDictMixin", + .basicsize = sizeof(PyDecSignalDictObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = signaldict_slots, }; @@ -987,7 +990,8 @@ context_settraps_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { @@ -1051,7 +1055,8 @@ context_setstatus_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { @@ -1241,8 +1246,9 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) PyDecContextObject *self = NULL; mpd_context_t *ctx; - if (type == &PyDecContext_Type) { - self = PyObject_New(PyDecContextObject, &PyDecContext_Type); + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDecContext_Type) { + self = PyObject_GC_New(PyDecContextObject, state->PyDecContext_Type); } else { self = (PyDecContextObject *)type->tp_alloc(type, 0); @@ -1252,13 +1258,13 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) return NULL; } - self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->traps = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->traps == NULL) { self->flags = NULL; Py_DECREF(self); return NULL; } - self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->flags = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->flags == NULL) { Py_DECREF(self); return NULL; @@ -1282,18 +1288,37 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) return (PyObject *)self; } +static int +context_traverse(PyDecContextObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->traps); + Py_VISIT(self->flags); + return 0; +} + +static int +context_clear(PyDecContextObject *self) +{ + Py_CLEAR(self->traps); + Py_CLEAR(self->flags); + return 0; +} + static void context_dealloc(PyDecContextObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); #ifndef WITH_DECIMAL_CONTEXTVAR - if (self == cached_context) { - cached_context = NULL; + decimal_state *state = GLOBAL_STATE(); + if (self == state->cached_context) { + state->cached_context = NULL; } #endif - - Py_XDECREF(self->traps); - Py_XDECREF(self->flags); - Py_TYPE(self)->tp_free(self); + (void)context_clear(self); + tp->tp_free(self); + Py_DECREF(tp); } static int @@ -1337,7 +1362,10 @@ context_repr(PyDecContextObject *self) char traps[MPD_MAX_SIGNAL_LIST]; int n, mem; - assert(PyDecContext_Check(self)); +#ifdef Py_DEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyDecContext_Check(state, self)); +#endif ctx = CTX(self); mem = MPD_MAX_SIGNAL_LIST; @@ -1403,7 +1431,8 @@ ieee_context(PyObject *dummy UNUSED, PyObject *v) goto error; } - context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = GLOBAL_STATE(); + context = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (context == NULL) { return NULL; } @@ -1425,7 +1454,8 @@ context_copy(PyObject *self, PyObject *args UNUSED) { PyObject *copy; - copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = GLOBAL_STATE(); + copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (copy == NULL) { return NULL; } @@ -1487,18 +1517,18 @@ static PyGetSetDef context_getsets [] = }; -#define CONTEXT_CHECK(obj) \ - if (!PyDecContext_Check(obj)) { \ +#define CONTEXT_CHECK(state, obj) \ + if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "argument must be a context"); \ return NULL; \ } -#define CONTEXT_CHECK_VA(obj) \ +#define CONTEXT_CHECK_VA(state, obj) \ if (obj == Py_None) { \ CURRENT_CONTEXT(obj); \ } \ - else if (!PyDecContext_Check(obj)) { \ + else if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "optional argument must be a context"); \ return NULL; \ @@ -1522,6 +1552,7 @@ static PyObject * current_context_from_dict(void) { PyThreadState *tstate = _PyThreadState_GET(); + decimal_state *modstate = GLOBAL_STATE(); #ifdef Py_DEBUG // The caller must hold the GIL _Py_EnsureTstateNotNULL(tstate); @@ -1537,7 +1568,7 @@ current_context_from_dict(void) PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ - CONTEXT_CHECK(tl_context); + CONTEXT_CHECK(modstate, tl_context); } else { if (PyErr_Occurred()) { @@ -1606,7 +1637,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { PyObject *dict; - CONTEXT_CHECK(v); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, v); dict = PyThreadState_GetDict(); if (dict == NULL) { @@ -1693,7 +1725,8 @@ PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) static PyObject * PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { - CONTEXT_CHECK(v); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, v); /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ @@ -1733,7 +1766,6 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) "clamp", "flags", "traps", NULL }; - PyDecContextManagerObject *self; PyObject *local = Py_None; PyObject *global; @@ -1746,6 +1778,7 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) PyObject *flags = Py_None; PyObject *traps = Py_None; + decimal_state *state = GLOBAL_STATE(); CURRENT_CONTEXT(global); if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, &local, &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) { @@ -1754,46 +1787,68 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) if (local == Py_None) { local = global; } - else if (!PyDecContext_Check(local)) { + else if (!PyDecContext_Check(state, local)) { PyErr_SetString(PyExc_TypeError, "optional argument must be a context"); return NULL; } - self = PyObject_New(PyDecContextManagerObject, - &PyDecContextManager_Type); - if (self == NULL) { - return NULL; - } - - self->local = context_copy(local, NULL); - if (self->local == NULL) { - self->global = NULL; - Py_DECREF(self); + PyObject *local_copy = context_copy(local, NULL); + if (local_copy == NULL) { return NULL; } - self->global = Py_NewRef(global); int ret = context_setattrs( - self->local, prec, rounding, + local_copy, prec, rounding, Emin, Emax, capitals, clamp, flags, traps ); - if (ret < 0) { - Py_DECREF(self); + Py_DECREF(local_copy); return NULL; } + PyDecContextManagerObject *self; + self = PyObject_GC_New(PyDecContextManagerObject, + state->PyDecContextManager_Type); + if (self == NULL) { + Py_DECREF(local_copy); + return NULL; + } + + self->local = local_copy; + self->global = Py_NewRef(global); + PyObject_GC_Track(self); + return (PyObject *)self; } +static int +ctxmanager_traverse(PyDecContextManagerObject *self, visitproc visit, + void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->local); + Py_VISIT(self->global); + return 0; +} + +static int +ctxmanager_clear(PyDecContextManagerObject *self) +{ + Py_CLEAR(self->local); + Py_CLEAR(self->global); + return 0; +} + static void ctxmanager_dealloc(PyDecContextManagerObject *self) { - Py_XDECREF(self->local); - Py_XDECREF(self->global); - PyObject_Free(self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)ctxmanager_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -1832,36 +1887,21 @@ static PyMethodDef ctxmanager_methods[] = { {NULL, NULL} }; -static PyTypeObject PyDecContextManager_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.ContextManager", /* tp_name */ - sizeof(PyDecContextManagerObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) ctxmanager_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctxmanager_methods, /* tp_methods */ +static PyType_Slot ctxmanager_slots[] = { + {Py_tp_dealloc, ctxmanager_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, ctxmanager_traverse}, + {Py_tp_clear, ctxmanager_clear}, + {Py_tp_methods, ctxmanager_methods}, + {0, NULL}, +}; + +static PyType_Spec ctxmanager_spec = { + .name = "decimal.ContextManager", + .basicsize = sizeof(PyDecContextManagerObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION), + .slots = ctxmanager_slots, }; @@ -1874,8 +1914,9 @@ PyDecType_New(PyTypeObject *type) { PyDecObject *dec; - if (type == &PyDec_Type) { - dec = PyObject_New(PyDecObject, &PyDec_Type); + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDec_Type) { + dec = PyObject_GC_New(PyDecObject, state->PyDec_Type); } else { dec = (PyDecObject *)type->tp_alloc(type, 0); @@ -1895,13 +1936,23 @@ PyDecType_New(PyTypeObject *type) return (PyObject *)dec; } -#define dec_alloc() PyDecType_New(&PyDec_Type) +#define dec_alloc(st) PyDecType_New((st)->PyDec_Type) + +static int +dec_traverse(PyObject *dec, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(dec)); + return 0; +} static void dec_dealloc(PyObject *dec) { + PyTypeObject *tp = Py_TYPE(dec); + PyObject_GC_UnTrack(dec); mpd_del(MPD(dec)); - Py_TYPE(dec)->tp_free(dec); + tp->tp_free(dec); + Py_DECREF(tp); } @@ -2259,9 +2310,10 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, uint32_t status = 0; mpd_context_t maxctx; - - assert(PyType_IsSubtype(type, &PyDec_Type)); - +#ifdef Py_DEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyType_IsSubtype(type, state->PyDec_Type)); +#endif if (PyLong_Check(v)) { return PyDecType_FromLongExact(type, v, context); } @@ -2395,7 +2447,8 @@ PyDecType_FromDecimalExact(PyTypeObject *type, PyObject *v, PyObject *context) PyObject *dec; uint32_t status = 0; - if (type == &PyDec_Type && PyDec_CheckExact(v)) { + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDec_Type && PyDec_CheckExact(state, v)) { return Py_NewRef(v); } @@ -2630,37 +2683,37 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, return dec; } -#define PyDec_FromCString(str, context) \ - PyDecType_FromCString(&PyDec_Type, str, context) -#define PyDec_FromCStringExact(str, context) \ - PyDecType_FromCStringExact(&PyDec_Type, str, context) +#define PyDec_FromCString(st, str, context) \ + PyDecType_FromCString((st)->PyDec_Type, str, context) +#define PyDec_FromCStringExact(st, str, context) \ + PyDecType_FromCStringExact((st)->PyDec_Type, str, context) -#define PyDec_FromUnicode(unicode, context) \ - PyDecType_FromUnicode(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExact(unicode, context) \ - PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExactWS(unicode, context) \ - PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context) +#define PyDec_FromUnicode(st, unicode, context) \ + PyDecType_FromUnicode((st)->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExact(st, unicode, context) \ + PyDecType_FromUnicodeExact((st)->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExactWS(st, unicode, context) \ + PyDecType_FromUnicodeExactWS((st)->PyDec_Type, unicode, context) -#define PyDec_FromSsize(v, context) \ - PyDecType_FromSsize(&PyDec_Type, v, context) -#define PyDec_FromSsizeExact(v, context) \ - PyDecType_FromSsizeExact(&PyDec_Type, v, context) +#define PyDec_FromSsize(st, v, context) \ + PyDecType_FromSsize((st)->PyDec_Type, v, context) +#define PyDec_FromSsizeExact(st, v, context) \ + PyDecType_FromSsizeExact((st)->PyDec_Type, v, context) -#define PyDec_FromLong(pylong, context) \ - PyDecType_FromLong(&PyDec_Type, pylong, context) -#define PyDec_FromLongExact(pylong, context) \ - PyDecType_FromLongExact(&PyDec_Type, pylong, context) +#define PyDec_FromLong(st, pylong, context) \ + PyDecType_FromLong((st)->PyDec_Type, pylong, context) +#define PyDec_FromLongExact(st, pylong, context) \ + PyDecType_FromLongExact((st)->PyDec_Type, pylong, context) -#define PyDec_FromFloat(pyfloat, context) \ - PyDecType_FromFloat(&PyDec_Type, pyfloat, context) -#define PyDec_FromFloatExact(pyfloat, context) \ - PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context) +#define PyDec_FromFloat(st, pyfloat, context) \ + PyDecType_FromFloat((st)->PyDec_Type, pyfloat, context) +#define PyDec_FromFloatExact(st, pyfloat, context) \ + PyDecType_FromFloatExact((st)->PyDec_Type, pyfloat, context) -#define PyDec_FromSequence(sequence, context) \ - PyDecType_FromSequence(&PyDec_Type, sequence, context) -#define PyDec_FromSequenceExact(sequence, context) \ - PyDecType_FromSequenceExact(&PyDec_Type, sequence, context) +#define PyDec_FromSequence(st, sequence, context) \ + PyDecType_FromSequence((st)->PyDec_Type, sequence, context) +#define PyDec_FromSequenceExact(st, sequence, context) \ + PyDecType_FromSequenceExact((st)->PyDec_Type, sequence, context) /* class method */ static PyObject * @@ -2670,8 +2723,9 @@ dec_from_float(PyObject *type, PyObject *pyfloat) PyObject *result; CURRENT_CONTEXT(context); - result = PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context); - if (type != (PyObject *)&PyDec_Type && result != NULL) { + decimal_state *state = GLOBAL_STATE(); + result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); + if (type != (PyObject *)state->PyDec_Type && result != NULL) { Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); } @@ -2682,7 +2736,8 @@ dec_from_float(PyObject *type, PyObject *pyfloat) static PyObject * ctx_from_float(PyObject *context, PyObject *v) { - return PyDec_FromFloat(v, context); + decimal_state *state = GLOBAL_STATE(); + return PyDec_FromFloat(state, v, context); } /* Apply the context to the input operand. Return a new PyDecObject. */ @@ -2692,7 +2747,8 @@ dec_apply(PyObject *v, PyObject *context) PyObject *result; uint32_t status = 0; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2718,10 +2774,11 @@ dec_apply(PyObject *v, PyObject *context) static PyObject * PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) { + decimal_state *state = GLOBAL_STATE(); if (v == NULL) { return PyDecType_FromSsizeExact(type, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { return PyDecType_FromDecimalExact(type, v, context); } else if (PyUnicode_Check(v)) { @@ -2752,10 +2809,11 @@ PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) static PyObject * PyDec_FromObject(PyObject *v, PyObject *context) { + decimal_state *state = GLOBAL_STATE(); if (v == NULL) { - return PyDec_FromSsize(0, context); + return PyDec_FromSsize(state, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { mpd_context_t *ctx = CTX(context); if (mpd_isnan(MPD(v)) && MPD(v)->digits > ctx->prec - ctx->clamp) { @@ -2764,7 +2822,7 @@ PyDec_FromObject(PyObject *v, PyObject *context) if (dec_addstatus(context, MPD_Conversion_syntax)) { return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2774,19 +2832,19 @@ PyDec_FromObject(PyObject *v, PyObject *context) return dec_apply(v, context); } else if (PyUnicode_Check(v)) { - return PyDec_FromUnicode(v, context); + return PyDec_FromUnicode(state, v, context); } else if (PyLong_Check(v)) { - return PyDec_FromLong(v, context); + return PyDec_FromLong(state, v, context); } else if (PyTuple_Check(v) || PyList_Check(v)) { - return PyDec_FromSequence(v, context); + return PyDec_FromSequence(state, v, context); } else if (PyFloat_Check(v)) { if (dec_addstatus(context, MPD_Float_operation)) { return NULL; } - return PyDec_FromFloat(v, context); + return PyDec_FromFloat(state, v, context); } else { PyErr_Format(PyExc_TypeError, @@ -2807,7 +2865,8 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) &v, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); return PyDecType_FromObjectExact(type, v, context); } @@ -2837,13 +2896,13 @@ ctx_create_decimal(PyObject *context, PyObject *args) Py_LOCAL_INLINE(int) convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) { - - if (PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDec_Check(state, v)) { *conv = Py_NewRef(v); return 1; } if (PyLong_Check(v)) { - *conv = PyDec_FromLongExact(v, context); + *conv = PyDec_FromLongExact(state, v, context); if (*conv == NULL) { return 0; } @@ -2942,7 +3001,8 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) if (tmp == NULL) { return NULL; } - denom = PyDec_FromLongExact(tmp, context); + decimal_state *state = GLOBAL_STATE(); + denom = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); if (denom == NULL) { return NULL; @@ -2954,7 +3014,7 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) PyErr_NoMemory(); return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(denom); mpd_del(vv); @@ -2996,7 +3056,8 @@ numerator_as_decimal(PyObject *r, PyObject *context) return NULL; } - num = PyDec_FromLongExact(tmp, context); + decimal_state *state = GLOBAL_STATE(); + num = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); return num; } @@ -3014,11 +3075,12 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, *vcmp = v; - if (PyDec_Check(w)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDec_Check(state, w)) { *wcmp = Py_NewRef(w); } else if (PyLong_Check(w)) { - *wcmp = PyDec_FromLongExact(w, context); + *wcmp = PyDec_FromLongExact(state, w, context); } else if (PyFloat_Check(w)) { if (op != Py_EQ && op != Py_NE && @@ -3027,7 +3089,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(w, context); + *wcmp = PyDec_FromFloatExact(state, w, context); } } else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) { @@ -3042,7 +3104,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(tmp, context); + *wcmp = PyDec_FromFloatExact(state, tmp, context); Py_DECREF(tmp); } } @@ -3556,7 +3618,8 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) CURRENT_CONTEXT(context); - tmp = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + tmp = dec_alloc(state); if (tmp == NULL) { return NULL; } @@ -3646,7 +3709,8 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -3659,7 +3723,7 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3687,7 +3751,8 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -3700,7 +3765,7 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3754,7 +3819,6 @@ PyDec_Round(PyObject *dec, PyObject *args) uint32_t status = 0; PyObject *context; - CURRENT_CONTEXT(context); if (!PyArg_ParseTuple(args, "|O", &x)) { return NULL; @@ -3775,7 +3839,8 @@ PyDec_Round(PyObject *dec, PyObject *args) if (y == -1 && PyErr_Occurred()) { return NULL; } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3794,7 +3859,6 @@ PyDec_Round(PyObject *dec, PyObject *args) } } -static PyTypeObject *DecimalTuple = NULL; /* Return the DecimalTuple representation of a PyDecObject. */ static PyObject * PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) @@ -3877,7 +3941,8 @@ PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) } } - result = PyObject_CallFunctionObjArgs((PyObject *)DecimalTuple, + decimal_state *state = GLOBAL_STATE(); + result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); out: @@ -3903,8 +3968,9 @@ nm_##MPDFUNC(PyObject *self) \ PyObject *context; \ uint32_t status = 0; \ \ + decimal_state *state = GLOBAL_STATE(); \ CURRENT_CONTEXT(context); \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -3927,10 +3993,11 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ PyObject *context; \ uint32_t status = 0; \ \ + decimal_state *state = GLOBAL_STATE(); \ CURRENT_CONTEXT(context) ; \ CONVERT_BINOP(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -3967,7 +4034,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ } @@ -3986,9 +4054,10 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -4017,10 +4086,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4054,10 +4124,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4086,10 +4157,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &third, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -4151,13 +4223,14 @@ nm_mpd_qdivmod(PyObject *v, PyObject *w) CURRENT_CONTEXT(context); CONVERT_BINOP(&a, &b, v, w, context); - q = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4199,7 +4272,8 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) } } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4300,7 +4374,8 @@ dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4315,7 +4390,8 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = GLOBAL_STATE(); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4335,7 +4411,8 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = GLOBAL_STATE(); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4364,7 +4441,8 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); cp = mpd_class(MPD(self), CTX(context)); return PyUnicode_FromString(cp); @@ -4383,7 +4461,8 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); if (size < 0) { @@ -4415,10 +4494,11 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4449,7 +4529,8 @@ dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); @@ -4483,7 +4564,8 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) &w, &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -4498,7 +4580,7 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) CONVERT_BINOP_RAISE(&a, &b, v, w, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4527,8 +4609,10 @@ dec_richcompare(PyObject *v, PyObject *w, int op) int a_issnan, b_issnan; int r; - assert(PyDec_Check(v)); - +#ifdef Py_DEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyDec_Check(state, v)); +#endif CURRENT_CONTEXT(context); CONVERT_BINOP_CMP(&a, &b, v, w, op, context); @@ -4798,7 +4882,8 @@ dec_imag(PyObject *self UNUSED, void *closure UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4815,43 +4900,6 @@ static PyGetSetDef dec_getsets [] = {NULL} }; -static PyNumberMethods dec_number_methods = -{ - (binaryfunc) nm_mpd_qadd, - (binaryfunc) nm_mpd_qsub, - (binaryfunc) nm_mpd_qmul, - (binaryfunc) nm_mpd_qrem, - (binaryfunc) nm_mpd_qdivmod, - (ternaryfunc) nm_mpd_qpow, - (unaryfunc) nm_mpd_qminus, - (unaryfunc) nm_mpd_qplus, - (unaryfunc) nm_mpd_qabs, - (inquiry) nm_nonzero, - (unaryfunc) 0, /* no bit-complement */ - (binaryfunc) 0, /* no shiftl */ - (binaryfunc) 0, /* no shiftr */ - (binaryfunc) 0, /* no bit-and */ - (binaryfunc) 0, /* no bit-xor */ - (binaryfunc) 0, /* no bit-ior */ - (unaryfunc) nm_dec_as_long, - 0, /* nb_reserved */ - (unaryfunc) PyDec_AsFloat, - 0, /* binaryfunc nb_inplace_add; */ - 0, /* binaryfunc nb_inplace_subtract; */ - 0, /* binaryfunc nb_inplace_multiply; */ - 0, /* binaryfunc nb_inplace_remainder; */ - 0, /* ternaryfunc nb_inplace_power; */ - 0, /* binaryfunc nb_inplace_lshift; */ - 0, /* binaryfunc nb_inplace_rshift; */ - 0, /* binaryfunc nb_inplace_and; */ - 0, /* binaryfunc nb_inplace_xor; */ - 0, /* binaryfunc nb_inplace_or; */ - (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */ - (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */ - 0, /* binaryfunc nb_inplace_floor_divide; */ - 0, /* binaryfunc nb_inplace_true_divide; */ -}; - static PyMethodDef dec_methods [] = { /* Unary arithmetic functions, optional context arg */ @@ -4944,48 +4992,44 @@ static PyMethodDef dec_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDec_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Decimal", /* tp_name */ - sizeof(PyDecObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) dec_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) dec_repr, /* tp_repr */ - &dec_number_methods, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) dec_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) dec_str, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - (Py_TPFLAGS_DEFAULT| - Py_TPFLAGS_BASETYPE), /* tp_flags */ - doc_decimal, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - dec_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dec_methods, /* tp_methods */ - 0, /* tp_members */ - dec_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dec_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot dec_slots[] = { + {Py_tp_dealloc, dec_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, dec_traverse}, + {Py_tp_repr, dec_repr}, + {Py_tp_hash, dec_hash}, + {Py_tp_str, dec_str}, + {Py_tp_doc, (void *)doc_decimal}, + {Py_tp_richcompare, dec_richcompare}, + {Py_tp_methods, dec_methods}, + {Py_tp_getset, dec_getsets}, + {Py_tp_new, dec_new}, + + // Number protocol + {Py_nb_add, nm_mpd_qadd}, + {Py_nb_subtract, nm_mpd_qsub}, + {Py_nb_multiply, nm_mpd_qmul}, + {Py_nb_remainder, nm_mpd_qrem}, + {Py_nb_divmod, nm_mpd_qdivmod}, + {Py_nb_power, nm_mpd_qpow}, + {Py_nb_negative, nm_mpd_qminus}, + {Py_nb_positive, nm_mpd_qplus}, + {Py_nb_absolute, nm_mpd_qabs}, + {Py_nb_bool, nm_nonzero}, + {Py_nb_int, nm_dec_as_long}, + {Py_nb_float, PyDec_AsFloat}, + {Py_nb_floor_divide, nm_mpd_qdivint}, + {Py_nb_true_divide, nm_mpd_qdiv}, + {0, NULL}, +}; + + +static PyType_Spec dec_spec = { + .name = "decimal.Decimal", + .basicsize = sizeof(PyDecObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = dec_slots, }; @@ -5037,8 +5081,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, v, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ } \ @@ -5068,8 +5112,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5103,8 +5147,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5132,8 +5176,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -5198,14 +5242,14 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - q = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5253,7 +5297,8 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5304,7 +5349,8 @@ DecCtx_BoolFunc_NO_CTX(mpd_iszero) static PyObject * ctx_iscanonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5329,7 +5375,8 @@ PyDecContext_Apply(PyObject *context, PyObject *v) static PyObject * ctx_canonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5345,8 +5392,8 @@ ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5378,8 +5425,8 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5475,8 +5522,8 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5629,47 +5676,27 @@ static PyMethodDef context_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDecContext_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Context", /* tp_name */ - sizeof(PyDecContextObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) context_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) context_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) context_getattr, /* tp_getattro */ - (setattrofunc) context_setattr, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - doc_context, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - context_methods, /* tp_methods */ - 0, /* tp_members */ - context_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - context_init, /* tp_init */ - 0, /* tp_alloc */ - context_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot context_slots[] = { + {Py_tp_dealloc, context_dealloc}, + {Py_tp_traverse, context_traverse}, + {Py_tp_clear, context_clear}, + {Py_tp_repr, context_repr}, + {Py_tp_getattro, context_getattr}, + {Py_tp_setattro, context_setattr}, + {Py_tp_doc, (void *)doc_context}, + {Py_tp_methods, context_methods}, + {Py_tp_getset, context_getsets}, + {Py_tp_init, context_init}, + {Py_tp_new, context_new}, + {0, NULL}, +}; + +static PyType_Spec context_spec = { + .name = "decimal.Context", + .basicsize = sizeof(PyDecContextObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = context_slots, }; @@ -5794,6 +5821,7 @@ PyInit__decimal(void) mpd_free = PyMem_Free; mpd_setminalloc(_Py_DEC_MINALLOC); + decimal_state *state = GLOBAL_STATE(); /* Init external C-API functions */ _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -5806,19 +5834,21 @@ PyInit__decimal(void) /* Init types */ - PyDec_Type.tp_base = &PyBaseObject_Type; - PyDecContext_Type.tp_base = &PyBaseObject_Type; - PyDecContextManager_Type.tp_base = &PyBaseObject_Type; - PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; +#define CREATE_TYPE(mod, tp, spec) do { \ + tp = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ + CHECK_PTR(tp); \ +} while (0) + + CREATE_TYPE(m, state->PyDec_Type, &dec_spec); + CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); + CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); + CREATE_TYPE(m, state->PyDecSignalDictMixin_Type, &signaldict_spec); - CHECK_INT(PyType_Ready(&PyDec_Type)); - CHECK_INT(PyType_Ready(&PyDecContext_Type)); - CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); - CHECK_INT(PyType_Ready(&PyDecContextManager_Type)); +#undef CREATE_TYPE ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); - CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict, + CHECK_INT(PyDict_SetItemString(state->PyDec_Type->tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->PyDecContext_Type->tp_dict, "__module__", obj)); Py_CLEAR(obj); @@ -5828,7 +5858,7 @@ PyInit__decimal(void) ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number")); /* Register Decimal with the Number abstract base class */ ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)", - (PyObject *)&PyDec_Type)); + (PyObject *)state->PyDec_Type)); Py_CLEAR(obj); /* Rational is a global variable used for fraction comparisons. */ ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); @@ -5838,12 +5868,12 @@ PyInit__decimal(void) /* DecimalTuple */ ASSIGN_PTR(collections, PyImport_ImportModule("collections")); - ASSIGN_PTR(DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, + ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, "namedtuple", "(ss)", "DecimalTuple", "sign digits exponent")); ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(DecimalTuple->tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->DecimalTuple->tp_dict, "__module__", obj)); Py_CLEAR(obj); /* MutableMapping */ @@ -5851,10 +5881,10 @@ PyInit__decimal(void) ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections_abc, "MutableMapping")); /* Create SignalDict type */ - ASSIGN_PTR(PyDecSignalDict_Type, + ASSIGN_PTR(state->PyDecSignalDict_Type, (PyTypeObject *)PyObject_CallFunction( (PyObject *)&PyType_Type, "s(OO){}", - "SignalDict", &PyDecSignalDictMixin_Type, + "SignalDict", state->PyDecSignalDictMixin_Type, MutableMapping)); /* Done with collections, MutableMapping */ @@ -5867,10 +5897,9 @@ PyInit__decimal(void) ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); /* Add types to the module */ - CHECK_INT(PyModule_AddObject(m, "Decimal", Py_NewRef(&PyDec_Type))); - CHECK_INT(PyModule_AddObject(m, "Context", - Py_NewRef(&PyDecContext_Type))); - CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); + CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); + CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); + CHECK_INT(PyModule_AddType(m, state->DecimalTuple)); /* Create top level exception */ ASSIGN_PTR(DecimalException, PyErr_NewException( @@ -5951,7 +5980,7 @@ PyInit__decimal(void) /* Init default context template first */ ASSIGN_PTR(default_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); CHECK_INT(PyModule_AddObject(m, "DefaultContext", Py_NewRef(default_context_template))); @@ -5966,14 +5995,14 @@ PyInit__decimal(void) /* Init basic context template */ ASSIGN_PTR(basic_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_basic_context(basic_context_template); CHECK_INT(PyModule_AddObject(m, "BasicContext", Py_NewRef(basic_context_template))); /* Init extended context template */ ASSIGN_PTR(extended_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_extended_context(extended_context_template); CHECK_INT(PyModule_AddObject(m, "ExtendedContext", Py_NewRef(extended_context_template))); @@ -6015,7 +6044,7 @@ PyInit__decimal(void) Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 7ca14b91c841d4..1131edff265ee4 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -375,10 +375,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDecContextManager_Type - -Modules/_decimal/_decimal.c - PyDecContext_Type - -Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - -Modules/_decimal/_decimal.c - PyDec_Type - Modules/xxmodule.c - Null_Type - Modules/xxmodule.c - Str_Type - Modules/xxmodule.c - Xxo_Type - @@ -389,8 +385,6 @@ Modules/xxsubtype.c - spamlist_type - ## non-static types - initialized once ## heap types -Modules/_decimal/_decimal.c - DecimalTuple - -Modules/_decimal/_decimal.c - PyDecSignalDict_Type - Modules/_tkinter.c - PyTclObject_Type - Modules/_tkinter.c - Tkapp_Type - Modules/_tkinter.c - Tktt_Type - @@ -428,6 +422,7 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - +Modules/_decimal/_decimal.c - global_state - Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - From 3c70d467c148875f2ce17bacab8909ecc3e9fc1d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jun 2023 17:22:15 +0300 Subject: [PATCH 183/446] Fix possible refleak in CodeType.replace() (GH-106243) A reference to c_code was leaked if PySys_Audit() failed. --- Objects/codeobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index a53584c4795e90..d2670c71caa44a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2035,6 +2035,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co_code, co_filename, co_name, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags) < 0) { + Py_XDECREF(code); return NULL; } From 8bff940ad69ce176dcd2b8e91d0b30ddd09945f1 Mon Sep 17 00:00:00 2001 From: hms <18321626+polynomialherder@users.noreply.github.com> Date: Thu, 29 Jun 2023 10:34:00 -0600 Subject: [PATCH 184/446] gh-105775: Convert LOAD_CLOSURE to a pseudo-op (#106059) This enables super-instruction formation, removal of checks for uninitialized variables, and frees up an instruction. --- Doc/library/dis.rst | 23 +- Include/internal/pycore_opcode.h | 15 +- Include/opcode.h | 22 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 3 +- Lib/test/test_compiler_assemble.py | 38 + Lib/test/test_dis.py | 16 +- ...-06-24-10-34-27.gh-issue-105775.OqjoGV.rst | 1 + PC/launcher.c | 1 + Python/bytecodes.c | 9 +- Python/compile.c | 2 + Python/executor_cases.c.h | 254 ++-- Python/flowgraph.c | 4 + Python/generated_cases.c.h | 1033 ++++++++--------- Python/opcode_metadata.h | 1 + Python/opcode_targets.h | 10 +- 16 files changed, 733 insertions(+), 702 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-24-10-34-27.gh-issue-105775.OqjoGV.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 39d43578faf3c3..63336bb9e08ead 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1291,18 +1291,6 @@ iterations of the loop. .. versionadded:: 3.11 -.. opcode:: LOAD_CLOSURE (i) - - Pushes a reference to the cell contained in slot ``i`` of the "fast locals" - storage. The name of the variable is ``co_fastlocalnames[i]``. - - Note that ``LOAD_CLOSURE`` is effectively an alias for ``LOAD_FAST``. - It exists to keep bytecode a little more readable. - - .. versionchanged:: 3.11 - ``i`` is no longer offset by the length of ``co_varnames``. - - .. opcode:: LOAD_DEREF (i) Loads the cell contained in slot ``i`` of the "fast locals" storage. @@ -1725,6 +1713,17 @@ but are replaced by real opcodes or removed before bytecode is generated. Undirected relative jump instructions which are replaced by their directed (forward/backward) counterparts by the assembler. +.. opcode:: LOAD_CLOSURE (i) + + Pushes a reference to the cell contained in slot ``i`` of the "fast locals" + storage. + + Note that ``LOAD_CLOSURE`` is replaced with ``LOAD_FAST`` in the assembler. + + .. versionchanged:: 3.13 + This opcode is now a pseudo-instruction. + + .. opcode:: LOAD_METHOD Optimized unbound method lookup. Emitted as a ``LOAD_ATTR`` opcode diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index cab5b587eda87d..bebdedc962403a 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -161,7 +161,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_ATTR_SLOT] = LOAD_ATTR, [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, [LOAD_BUILD_CLASS] = LOAD_BUILD_CLASS, - [LOAD_CLOSURE] = LOAD_CLOSURE, [LOAD_CONST] = LOAD_CONST, [LOAD_DEREF] = LOAD_DEREF, [LOAD_FAST] = LOAD_FAST, @@ -236,7 +235,7 @@ const uint8_t _PyOpcode_Deopt[256] = { #endif // NEED_OPCODE_TABLES #ifdef Py_DEBUG -static const char *const _PyOpcode_OpName[267] = { +static const char *const _PyOpcode_OpName[268] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", [PUSH_NULL] = "PUSH_NULL", @@ -373,7 +372,7 @@ static const char *const _PyOpcode_OpName[267] = { [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", - [LOAD_CLOSURE] = "LOAD_CLOSURE", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [LOAD_DEREF] = "LOAD_DEREF", [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", @@ -385,26 +384,26 @@ static const char *const _PyOpcode_OpName[267] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", [CONVERT_VALUE] = "CONVERT_VALUE", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT", + [167] = "<167>", [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST", [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST", [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST", @@ -504,10 +503,12 @@ static const char *const _PyOpcode_OpName[267] = { [LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD", [LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR", [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL", + [LOAD_CLOSURE] = "LOAD_CLOSURE", }; #endif #define EXTRA_CASES \ + case 167: \ case 178: \ case 179: \ case 180: \ diff --git a/Include/opcode.h b/Include/opcode.h index 3fe4fc0bb3404f..0533ae96688707 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -93,7 +93,6 @@ extern "C" { #define BUILD_SLICE 133 #define JUMP_BACKWARD_NO_INTERRUPT 134 #define MAKE_CELL 135 -#define LOAD_CLOSURE 136 #define LOAD_DEREF 137 #define STORE_DEREF 138 #define DELETE_DEREF 139 @@ -158,7 +157,8 @@ extern "C" { #define LOAD_ZERO_SUPER_METHOD 264 #define LOAD_ZERO_SUPER_ATTR 265 #define STORE_FAST_MAYBE_NULL 266 -#define MAX_PSEUDO_OPCODE 266 +#define LOAD_CLOSURE 267 +#define MAX_PSEUDO_OPCODE 267 #define BINARY_OP_MULTIPLY_INT 6 #define BINARY_OP_ADD_INT 7 #define BINARY_OP_SUBTRACT_INT 8 @@ -210,15 +210,15 @@ extern "C" { #define CALL_BUILTIN_CLASS 112 #define CALL_NO_KW_BUILTIN_O 113 #define CALL_NO_KW_BUILTIN_FAST 132 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 148 -#define CALL_NO_KW_LEN 153 -#define CALL_NO_KW_ISINSTANCE 154 -#define CALL_NO_KW_LIST_APPEND 155 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 159 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 160 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 161 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 166 -#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 167 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 136 +#define CALL_NO_KW_LEN 148 +#define CALL_NO_KW_ISINSTANCE 153 +#define CALL_NO_KW_LIST_APPEND 154 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 155 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 159 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 160 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 161 +#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 166 #define NB_ADD 0 #define NB_AND 1 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 6a3eabe1973ac8..8b4ac6ca012045 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -451,6 +451,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE) # Python 3.13a1 3554 (more efficient bytecodes for f-strings) # Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c) +# Python 3.13a1 3556 (Convert LOAD_CLOSURE to a pseudo-op) # Python 3.14 will start with 3600 @@ -467,7 +468,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 = (3555).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3556).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 392464ddab9728..52c566cd0cabc6 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -198,8 +198,6 @@ def pseudo_op(name, op, real_ops): jrel_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards) def_op('MAKE_CELL', 135) hasfree.append(135) -def_op('LOAD_CLOSURE', 136) -hasfree.append(136) def_op('LOAD_DEREF', 137) hasfree.append(137) def_op('STORE_DEREF', 138) @@ -293,6 +291,7 @@ def pseudo_op(name, op, real_ops): pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR']) pseudo_op('STORE_FAST_MAYBE_NULL', 266, ['STORE_FAST']) +pseudo_op('LOAD_CLOSURE', 267, ['LOAD_FAST']) MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1 diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py index 3257aa3cc118fc..6df72cbc54666b 100644 --- a/Lib/test/test_compiler_assemble.py +++ b/Lib/test/test_compiler_assemble.py @@ -70,3 +70,41 @@ def test_simple_expr(self): ] expected = {(3, 4) : 3.5, (-100, 200) : 50, (10, 18) : 14} self.assemble_test(insts, metadata, expected) + + + def test_expression_with_pseudo_instruction_load_closure(self): + + def mod_two(x): + def inner(): + return x + return inner() % 2 + + inner_code = mod_two.__code__.co_consts[1] + assert isinstance(inner_code, types.CodeType) + + metadata = { + 'filename' : 'mod_two.py', + 'name' : 'mod_two', + 'qualname' : 'nested.mod_two', + 'cellvars' : {'x' : 0}, + 'consts': {None: 0, inner_code: 1, 2: 2}, + 'argcount' : 1, + 'varnames' : {'x' : 0}, + } + + instructions = [ + ('RESUME', 0,), + ('PUSH_NULL', 0, 1), + ('LOAD_CLOSURE', 0, 1), + ('BUILD_TUPLE', 1, 1), + ('LOAD_CONST', 1, 1), + ('MAKE_FUNCTION', 0, 2), + ('SET_FUNCTION_ATTRIBUTE', 8, 2), + ('CALL', 0, 2), # (lambda: x)() + ('LOAD_CONST', 2, 2), # 2 + ('BINARY_OP', 6, 2), # % + ('RETURN_VALUE', 0, 2) + ] + + expected = {(0,): 0, (1,): 1, (2,): 0, (120,): 0, (121,): 1} + self.assemble_test(instructions, metadata, expected) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 7dd6e3f0d62439..ab8026b81fd3d6 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -685,7 +685,7 @@ def foo(x): %3d RESUME 0 -%3d LOAD_CLOSURE 0 (y) +%3d LOAD_FAST 0 (y) BUILD_TUPLE 1 LOAD_CONST 1 () MAKE_FUNCTION @@ -709,7 +709,7 @@ def foo(x): %3d RESUME 0 %3d LOAD_GLOBAL 1 (NULL + list) - LOAD_CLOSURE 0 (x) + LOAD_FAST 0 (x) BUILD_TUPLE 1 LOAD_CONST 1 ( at 0x..., file "%s", line %d>) MAKE_FUNCTION @@ -1596,8 +1596,8 @@ def _prepare_test_cases(): Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=1, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), @@ -1624,10 +1624,10 @@ def _prepare_test_cases(): Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=2, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=3, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='MAKE_FUNCTION', opcode=24, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=None, is_jump_target=False, positions=None), diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-24-10-34-27.gh-issue-105775.OqjoGV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-24-10-34-27.gh-issue-105775.OqjoGV.rst new file mode 100644 index 00000000000000..27d0e9929794f4 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-24-10-34-27.gh-issue-105775.OqjoGV.rst @@ -0,0 +1 @@ +:opcode:`LOAD_CLOSURE` is now a pseudo-op. \ No newline at end of file diff --git a/PC/launcher.c b/PC/launcher.c index dc265533740b67..8e60ab9303cb95 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -1270,6 +1270,7 @@ static PYC_MAGIC magic_values[] = { /* Allow 50 magic numbers per version from here on */ { 3450, 3499, L"3.11" }, { 3500, 3549, L"3.12" }, + { 3550, 3599, L"3.13" }, { 0 } }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 02857104f5a4d5..1d9664bc27d244 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -175,12 +175,9 @@ dummy_func( } } - inst(LOAD_CLOSURE, (-- value)) { - /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ - value = GETLOCAL(oparg); - ERROR_IF(value == NULL, unbound_local_error); - Py_INCREF(value); - } + pseudo(LOAD_CLOSURE) = { + LOAD_FAST, + }; inst(LOAD_FAST_CHECK, (-- value)) { value = GETLOCAL(oparg); diff --git a/Python/compile.c b/Python/compile.c index d080144121af7b..5936184d8b76b4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -836,6 +836,8 @@ stack_effect(int opcode, int oparg, int jump) case STORE_FAST_MAYBE_NULL: return -1; + case LOAD_CLOSURE: + return 1; case LOAD_METHOD: return 1; case LOAD_SUPER_METHOD: diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 739cb8499c0079..a64de0c958ce04 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9,7 +9,7 @@ case LOAD_FAST: { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 189 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -21,7 +21,7 @@ case LOAD_FAST_AND_CLEAR: { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 195 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -33,7 +33,7 @@ case LOAD_CONST: { PyObject *value; - #line 213 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 40 "Python/executor_cases.c.h" @@ -44,7 +44,7 @@ case STORE_FAST: { PyObject *value = stack_pointer[-1]; - #line 218 "Python/bytecodes.c" + #line 215 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 50 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -53,7 +53,7 @@ case POP_TOP: { PyObject *value = stack_pointer[-1]; - #line 241 "Python/bytecodes.c" + #line 238 "Python/bytecodes.c" #line 58 "Python/executor_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -62,7 +62,7 @@ case PUSH_NULL: { PyObject *res; - #line 245 "Python/bytecodes.c" + #line 242 "Python/bytecodes.c" res = NULL; #line 68 "Python/executor_cases.c.h" STACK_GROW(1); @@ -73,7 +73,7 @@ case END_SEND: { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 264 "Python/bytecodes.c" + #line 261 "Python/bytecodes.c" Py_DECREF(receiver); #line 79 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -84,11 +84,11 @@ case UNARY_NEGATIVE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 279 "Python/bytecodes.c" + #line 276 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 90 "Python/executor_cases.c.h" Py_DECREF(value); - #line 281 "Python/bytecodes.c" + #line 278 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 94 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -98,11 +98,11 @@ case UNARY_NOT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 285 "Python/bytecodes.c" + #line 282 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 104 "Python/executor_cases.c.h" Py_DECREF(value); - #line 287 "Python/bytecodes.c" + #line 284 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -118,11 +118,11 @@ case UNARY_INVERT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 297 "Python/bytecodes.c" + #line 294 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 124 "Python/executor_cases.c.h" Py_DECREF(value); - #line 299 "Python/bytecodes.c" + #line 296 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 128 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -132,7 +132,7 @@ case _GUARD_BOTH_INT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 315 "Python/bytecodes.c" + #line 312 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 139 "Python/executor_cases.c.h" @@ -143,7 +143,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 320 "Python/bytecodes.c" + #line 317 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -159,7 +159,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 328 "Python/bytecodes.c" + #line 325 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -175,7 +175,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 336 "Python/bytecodes.c" + #line 333 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -190,7 +190,7 @@ case _GUARD_BOTH_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 351 "Python/bytecodes.c" + #line 348 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 197 "Python/executor_cases.c.h" @@ -201,7 +201,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 356 "Python/bytecodes.c" + #line 353 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -217,7 +217,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 364 "Python/bytecodes.c" + #line 361 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -233,7 +233,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 372 "Python/bytecodes.c" + #line 369 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -248,7 +248,7 @@ case _GUARD_BOTH_UNICODE: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 387 "Python/bytecodes.c" + #line 384 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 255 "Python/executor_cases.c.h" @@ -259,7 +259,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 392 "Python/bytecodes.c" + #line 389 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -276,7 +276,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 462 "Python/bytecodes.c" + #line 459 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -300,7 +300,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 477 "Python/bytecodes.c" + #line 474 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -322,7 +322,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 492 "Python/bytecodes.c" + #line 489 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -346,7 +346,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 508 "Python/bytecodes.c" + #line 505 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -370,7 +370,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 524 "Python/bytecodes.c" + #line 521 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -381,7 +381,7 @@ #line 382 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 532 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -396,7 +396,7 @@ case LIST_APPEND: { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 564 "Python/bytecodes.c" + #line 561 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 402 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -406,11 +406,11 @@ case SET_ADD: { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 568 "Python/bytecodes.c" + #line 565 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 412 "Python/executor_cases.c.h" Py_DECREF(v); - #line 570 "Python/bytecodes.c" + #line 567 "Python/bytecodes.c" if (err) goto pop_1_error; #line 416 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -421,7 +421,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 599 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -447,7 +447,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 618 "Python/bytecodes.c" + #line 615 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -461,13 +461,13 @@ case DELETE_SUBSCR: { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 626 "Python/bytecodes.c" + #line 623 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 468 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 629 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" if (err) goto pop_2_error; #line 473 "Python/executor_cases.c.h" STACK_SHRINK(2); @@ -477,12 +477,12 @@ case CALL_INTRINSIC_1: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 633 "Python/bytecodes.c" + #line 630 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 484 "Python/executor_cases.c.h" Py_DECREF(value); - #line 636 "Python/bytecodes.c" + #line 633 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 488 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -493,13 +493,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 640 "Python/bytecodes.c" + #line 637 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 500 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 643 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 505 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -510,7 +510,7 @@ case GET_AITER: { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 748 "Python/bytecodes.c" + #line 745 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -525,14 +525,14 @@ type->tp_name); #line 527 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 761 "Python/bytecodes.c" + #line 758 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 534 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 766 "Python/bytecodes.c" + #line 763 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -553,7 +553,7 @@ case GET_ANEXT: { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 781 "Python/bytecodes.c" + #line 778 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -605,7 +605,7 @@ case GET_AWAITABLE: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 826 "Python/bytecodes.c" + #line 823 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -614,7 +614,7 @@ #line 616 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 833 "Python/bytecodes.c" + #line 830 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -638,7 +638,7 @@ case POP_EXCEPT: { PyObject *exc_value = stack_pointer[-1]; - #line 963 "Python/bytecodes.c" + #line 960 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 645 "Python/executor_cases.c.h" @@ -648,7 +648,7 @@ case LOAD_ASSERTION_ERROR: { PyObject *value; - #line 1014 "Python/bytecodes.c" + #line 1011 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 654 "Python/executor_cases.c.h" STACK_GROW(1); @@ -658,7 +658,7 @@ case LOAD_BUILD_CLASS: { PyObject *bc; - #line 1018 "Python/bytecodes.c" + #line 1015 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -688,7 +688,7 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; - #line 1043 "Python/bytecodes.c" + #line 1040 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -697,7 +697,7 @@ "no locals found when storing %R", name); #line 699 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1050 "Python/bytecodes.c" + #line 1047 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -706,7 +706,7 @@ err = PyObject_SetItem(ns, name, v); #line 708 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1057 "Python/bytecodes.c" + #line 1054 "Python/bytecodes.c" if (err) goto pop_1_error; #line 712 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -714,7 +714,7 @@ } case DELETE_NAME: { - #line 1061 "Python/bytecodes.c" + #line 1058 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -738,7 +738,7 @@ case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1104 "Python/bytecodes.c" + #line 1101 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -755,7 +755,7 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1114 "Python/bytecodes.c" + #line 1111 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -773,7 +773,7 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1125 "Python/bytecodes.c" + #line 1122 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -790,13 +790,13 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; - #line 1136 "Python/bytecodes.c" + #line 1133 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 798 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1140 "Python/bytecodes.c" + #line 1137 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 802 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -805,12 +805,12 @@ case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; - #line 1171 "Python/bytecodes.c" + #line 1168 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 812 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1174 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" if (err) goto pop_1_error; #line 816 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -819,12 +819,12 @@ case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; - #line 1178 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 826 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1181 "Python/bytecodes.c" + #line 1178 "Python/bytecodes.c" if (err) goto pop_1_error; #line 830 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -832,7 +832,7 @@ } case DELETE_GLOBAL: { - #line 1185 "Python/bytecodes.c" + #line 1182 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -850,7 +850,7 @@ case _LOAD_LOCALS: { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -867,7 +867,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; - #line 1211 "Python/bytecodes.c" + #line 1208 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -930,7 +930,7 @@ } case DELETE_DEREF: { - #line 1381 "Python/bytecodes.c" + #line 1378 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -948,7 +948,7 @@ case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1394 "Python/bytecodes.c" + #line 1391 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -990,7 +990,7 @@ case LOAD_DEREF: { PyObject *value; - #line 1431 "Python/bytecodes.c" + #line 1428 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1006,7 +1006,7 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1441 "Python/bytecodes.c" + #line 1438 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -1017,7 +1017,7 @@ } case COPY_FREE_VARS: { - #line 1448 "Python/bytecodes.c" + #line 1445 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1035,13 +1035,13 @@ case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1461 "Python/bytecodes.c" + #line 1458 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 1041 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1463 "Python/bytecodes.c" + #line 1460 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 1047 "Python/executor_cases.c.h" STACK_SHRINK(oparg); @@ -1053,7 +1053,7 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1467 "Python/bytecodes.c" + #line 1464 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 1060 "Python/executor_cases.c.h" @@ -1066,7 +1066,7 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1472 "Python/bytecodes.c" + #line 1469 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 1073 "Python/executor_cases.c.h" @@ -1079,7 +1079,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1477 "Python/bytecodes.c" + #line 1474 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1092,7 +1092,7 @@ } #line 1094 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1488 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -1105,11 +1105,11 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1495 "Python/bytecodes.c" + #line 1492 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 1111 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1497 "Python/bytecodes.c" + #line 1494 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 1115 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -1119,7 +1119,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1501 "Python/bytecodes.c" + #line 1498 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1144,7 +1144,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1518 "Python/bytecodes.c" + #line 1515 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1156,7 +1156,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1526 "Python/bytecodes.c" + #line 1523 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 1162 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); @@ -1166,7 +1166,7 @@ } case SETUP_ANNOTATIONS: { - #line 1530 "Python/bytecodes.c" + #line 1527 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1214,7 +1214,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1572 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1229,7 +1229,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1582 "Python/bytecodes.c" + #line 1579 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 1235 "Python/executor_cases.c.h" STACK_SHRINK(oparg); @@ -1239,7 +1239,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1586 "Python/bytecodes.c" + #line 1583 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1249,7 +1249,7 @@ } #line 1251 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1594 "Python/bytecodes.c" + #line 1591 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1256 "Python/executor_cases.c.h" @@ -1260,14 +1260,14 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1600 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 1269 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1605 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1274 "Python/executor_cases.c.h" @@ -1279,7 +1279,7 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1611 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -1296,7 +1296,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1694 "Python/bytecodes.c" + #line 1691 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1307,7 +1307,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1701 "Python/bytecodes.c" + #line 1698 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 1313 "Python/executor_cases.c.h" STACK_SHRINK(2); @@ -1323,7 +1323,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1702 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1357,7 +1357,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2037 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1378,7 +1378,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2051 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1403,7 +1403,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2069 "Python/bytecodes.c" + #line 2066 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1425,12 +1425,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2083 "Python/bytecodes.c" + #line 2080 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 1431 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2085 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1436 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -1442,12 +1442,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2089 "Python/bytecodes.c" + #line 2086 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 1448 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2091 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 1454 "Python/executor_cases.c.h" @@ -1461,12 +1461,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2096 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 1467 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2098 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1477,7 +1477,7 @@ #line 1478 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2106 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1496,19 +1496,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2117 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 1503 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2120 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 1510 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2125 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1514 "Python/executor_cases.c.h" stack_pointer[-1] = b; @@ -1518,7 +1518,7 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2246 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -1535,7 +1535,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2254 "Python/bytecodes.c" + #line 2251 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -1544,7 +1544,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2259 "Python/bytecodes.c" + #line 2256 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1561,7 +1561,7 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2269 "Python/bytecodes.c" + #line 2266 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 1568 "Python/executor_cases.c.h" @@ -1573,7 +1573,7 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2274 "Python/bytecodes.c" + #line 2271 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 1580 "Python/executor_cases.c.h" @@ -1586,7 +1586,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2279 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -1599,12 +1599,12 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2285 "Python/bytecodes.c" + #line 2282 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 1606 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2288 "Python/bytecodes.c" + #line 2285 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 1610 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1614,7 +1614,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2292 "Python/bytecodes.c" + #line 2289 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1639,7 +1639,7 @@ } #line 1641 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2315 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" } #line 1645 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1651,7 +1651,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2547 "Python/bytecodes.c" + #line 2544 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -1681,7 +1681,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2586 "Python/bytecodes.c" + #line 2583 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -1700,7 +1700,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 2955 "Python/bytecodes.c" + #line 2952 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1716,7 +1716,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3369 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1736,7 +1736,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3383 "Python/bytecodes.c" + #line 3380 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1772,13 +1772,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3433 "Python/bytecodes.c" + #line 3430 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 1778 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3435 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 1784 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -1790,7 +1790,7 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3439 "Python/bytecodes.c" + #line 3436 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -1805,7 +1805,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3448 "Python/bytecodes.c" + #line 3445 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1825,7 +1825,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3461 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -1839,7 +1839,7 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3468 "Python/bytecodes.c" + #line 3465 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 1846 "Python/executor_cases.c.h" @@ -1851,7 +1851,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3493 "Python/bytecodes.c" + #line 3490 "Python/bytecodes.c" assert(oparg >= 2); #line 1857 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index a6b2a9f275a70a..d78fb92e0d67dd 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -2002,6 +2002,10 @@ _PyCfg_ConvertPseudoOps(basicblock *entryblock) assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP)); INSTR_SET_OP0(instr, NOP); } + else if (instr->i_opcode == LOAD_CLOSURE) { + assert(SAME_OPCODE_METADATA(LOAD_CLOSURE, LOAD_FAST)); + instr->i_opcode = LOAD_FAST; + } else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) { assert(SAME_OPCODE_METADATA(STORE_FAST_MAYBE_NULL, STORE_FAST)); instr->i_opcode = STORE_FAST; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 43cfd4a882c73a..44b4522c9a5f1e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -55,26 +55,13 @@ DISPATCH(); } - TARGET(LOAD_CLOSURE) { - PyObject *value; - #line 179 "Python/bytecodes.c" - /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ - value = GETLOCAL(oparg); - if (value == NULL) goto unbound_local_error; - Py_INCREF(value); - #line 66 "Python/generated_cases.c.h" - STACK_GROW(1); - stack_pointer[-1] = value; - DISPATCH(); - } - TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 186 "Python/bytecodes.c" + #line 183 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - #line 78 "Python/generated_cases.c.h" + #line 65 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -82,11 +69,11 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 192 "Python/bytecodes.c" + #line 189 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 90 "Python/generated_cases.c.h" + #line 77 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -94,11 +81,11 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 198 "Python/bytecodes.c" + #line 195 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; - #line 102 "Python/generated_cases.c.h" + #line 89 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -107,14 +94,14 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 204 "Python/bytecodes.c" + #line 201 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); value2 = GETLOCAL(oparg2); Py_INCREF(value1); Py_INCREF(value2); - #line 118 "Python/generated_cases.c.h" + #line 105 "Python/generated_cases.c.h" STACK_GROW(2); stack_pointer[-1] = value2; stack_pointer[-2] = value1; @@ -123,10 +110,10 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 213 "Python/bytecodes.c" + #line 210 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); - #line 130 "Python/generated_cases.c.h" + #line 117 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -134,9 +121,9 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 218 "Python/bytecodes.c" + #line 215 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 140 "Python/generated_cases.c.h" + #line 127 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -144,13 +131,13 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 226 "Python/bytecodes.c" + #line 223 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); value2 = GETLOCAL(oparg2); Py_INCREF(value2); - #line 154 "Python/generated_cases.c.h" + #line 141 "Python/generated_cases.c.h" stack_pointer[-1] = value2; DISPATCH(); } @@ -158,20 +145,20 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 234 "Python/bytecodes.c" + #line 231 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); SETLOCAL(oparg2, value2); - #line 167 "Python/generated_cases.c.h" + #line 154 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 241 "Python/bytecodes.c" - #line 175 "Python/generated_cases.c.h" + #line 238 "Python/bytecodes.c" + #line 162 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -179,9 +166,9 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 245 "Python/bytecodes.c" + #line 242 "Python/bytecodes.c" res = NULL; - #line 185 "Python/generated_cases.c.h" + #line 172 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -192,14 +179,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 241 "Python/bytecodes.c" - #line 197 "Python/generated_cases.c.h" + #line 238 "Python/bytecodes.c" + #line 184 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 241 "Python/bytecodes.c" - #line 203 "Python/generated_cases.c.h" + #line 238 "Python/bytecodes.c" + #line 190 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); @@ -209,7 +196,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 251 "Python/bytecodes.c" + #line 248 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -219,7 +206,7 @@ } PyErr_SetRaisedException(NULL); } - #line 223 "Python/generated_cases.c.h" + #line 210 "Python/generated_cases.c.h" Py_DECREF(receiver); Py_DECREF(value); STACK_SHRINK(2); @@ -229,9 +216,9 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 264 "Python/bytecodes.c" + #line 261 "Python/bytecodes.c" Py_DECREF(receiver); - #line 235 "Python/generated_cases.c.h" + #line 222 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -240,7 +227,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 268 "Python/bytecodes.c" + #line 265 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -249,7 +236,7 @@ PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); - #line 253 "Python/generated_cases.c.h" + #line 240 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -258,13 +245,13 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 279 "Python/bytecodes.c" + #line 276 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 264 "Python/generated_cases.c.h" + #line 251 "Python/generated_cases.c.h" Py_DECREF(value); - #line 281 "Python/bytecodes.c" + #line 278 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 268 "Python/generated_cases.c.h" + #line 255 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -272,11 +259,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 285 "Python/bytecodes.c" + #line 282 "Python/bytecodes.c" int err = PyObject_IsTrue(value); - #line 278 "Python/generated_cases.c.h" + #line 265 "Python/generated_cases.c.h" Py_DECREF(value); - #line 287 "Python/bytecodes.c" + #line 284 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -284,7 +271,7 @@ else { res = Py_False; } - #line 288 "Python/generated_cases.c.h" + #line 275 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -292,13 +279,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 297 "Python/bytecodes.c" + #line 294 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 298 "Python/generated_cases.c.h" + #line 285 "Python/generated_cases.c.h" Py_DECREF(value); - #line 299 "Python/bytecodes.c" + #line 296 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 302 "Python/generated_cases.c.h" + #line 289 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -309,10 +296,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 312 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 316 "Python/generated_cases.c.h" + #line 303 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -320,13 +307,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 320 "Python/bytecodes.c" + #line 317 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 330 "Python/generated_cases.c.h" + #line 317 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -341,10 +328,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 312 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 348 "Python/generated_cases.c.h" + #line 335 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -352,13 +339,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 328 "Python/bytecodes.c" + #line 325 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 362 "Python/generated_cases.c.h" + #line 349 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -373,10 +360,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 315 "Python/bytecodes.c" + #line 312 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 380 "Python/generated_cases.c.h" + #line 367 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -384,13 +371,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 336 "Python/bytecodes.c" + #line 333 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 394 "Python/generated_cases.c.h" + #line 381 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -405,10 +392,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 348 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 412 "Python/generated_cases.c.h" + #line 399 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -416,13 +403,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 356 "Python/bytecodes.c" + #line 353 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 426 "Python/generated_cases.c.h" + #line 413 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -437,10 +424,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 348 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 444 "Python/generated_cases.c.h" + #line 431 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -448,13 +435,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 364 "Python/bytecodes.c" + #line 361 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 458 "Python/generated_cases.c.h" + #line 445 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -469,10 +456,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 351 "Python/bytecodes.c" + #line 348 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 476 "Python/generated_cases.c.h" + #line 463 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -480,13 +467,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 372 "Python/bytecodes.c" + #line 369 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 490 "Python/generated_cases.c.h" + #line 477 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -501,10 +488,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 384 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 508 "Python/generated_cases.c.h" + #line 495 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -512,13 +499,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 392 "Python/bytecodes.c" + #line 389 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 522 "Python/generated_cases.c.h" + #line 509 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -533,17 +520,17 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 384 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 540 "Python/generated_cases.c.h" + #line 527 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 409 "Python/bytecodes.c" + #line 406 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -567,7 +554,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 571 "Python/generated_cases.c.h" + #line 558 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -579,7 +566,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 446 "Python/bytecodes.c" + #line 443 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -591,12 +578,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 595 "Python/generated_cases.c.h" + #line 582 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 458 "Python/bytecodes.c" + #line 455 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 600 "Python/generated_cases.c.h" + #line 587 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -608,7 +595,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 462 "Python/bytecodes.c" + #line 459 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -621,7 +608,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 625 "Python/generated_cases.c.h" + #line 612 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -632,7 +619,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 477 "Python/bytecodes.c" + #line 474 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -645,7 +632,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 649 "Python/generated_cases.c.h" + #line 636 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -654,7 +641,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 492 "Python/bytecodes.c" + #line 489 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -668,7 +655,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 672 "Python/generated_cases.c.h" + #line 659 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -679,7 +666,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 508 "Python/bytecodes.c" + #line 505 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -693,7 +680,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 697 "Python/generated_cases.c.h" + #line 684 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -704,7 +691,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 524 "Python/bytecodes.c" + #line 521 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -712,14 +699,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 716 "Python/generated_cases.c.h" + #line 703 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 532 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 723 "Python/generated_cases.c.h" + #line 710 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -731,7 +718,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 539 "Python/bytecodes.c" + #line 536 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -754,15 +741,15 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 758 "Python/generated_cases.c.h" + #line 745 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 564 "Python/bytecodes.c" + #line 561 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 766 "Python/generated_cases.c.h" + #line 753 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -770,13 +757,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 568 "Python/bytecodes.c" + #line 565 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 776 "Python/generated_cases.c.h" + #line 763 "Python/generated_cases.c.h" Py_DECREF(v); - #line 570 "Python/bytecodes.c" + #line 567 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 780 "Python/generated_cases.c.h" + #line 767 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -788,7 +775,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 580 "Python/bytecodes.c" + #line 577 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -803,13 +790,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 807 "Python/generated_cases.c.h" + #line 794 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 595 "Python/bytecodes.c" + #line 592 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 813 "Python/generated_cases.c.h" + #line 800 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -819,7 +806,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 599 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -836,7 +823,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 840 "Python/generated_cases.c.h" + #line 827 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -846,13 +833,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 618 "Python/bytecodes.c" + #line 615 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 856 "Python/generated_cases.c.h" + #line 843 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -861,15 +848,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 626 "Python/bytecodes.c" + #line 623 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 868 "Python/generated_cases.c.h" + #line 855 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 629 "Python/bytecodes.c" + #line 626 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 873 "Python/generated_cases.c.h" + #line 860 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -877,14 +864,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 633 "Python/bytecodes.c" + #line 630 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 884 "Python/generated_cases.c.h" + #line 871 "Python/generated_cases.c.h" Py_DECREF(value); - #line 636 "Python/bytecodes.c" + #line 633 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 888 "Python/generated_cases.c.h" + #line 875 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -893,15 +880,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 640 "Python/bytecodes.c" + #line 637 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 900 "Python/generated_cases.c.h" + #line 887 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 643 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 905 "Python/generated_cases.c.h" + #line 892 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -909,7 +896,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 647 "Python/bytecodes.c" + #line 644 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -927,12 +914,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 931 "Python/generated_cases.c.h" + #line 918 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 667 "Python/bytecodes.c" + #line 664 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -941,12 +928,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 945 "Python/generated_cases.c.h" + #line 932 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 678 "Python/bytecodes.c" + #line 675 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -959,12 +946,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 963 "Python/generated_cases.c.h" + #line 950 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 693 "Python/bytecodes.c" + #line 690 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -981,11 +968,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 985 "Python/generated_cases.c.h" + #line 972 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 712 "Python/bytecodes.c" + #line 709 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -999,11 +986,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1003 "Python/generated_cases.c.h" + #line 990 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 728 "Python/bytecodes.c" + #line 725 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1021,13 +1008,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1025 "Python/generated_cases.c.h" + #line 1012 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 748 "Python/bytecodes.c" + #line 745 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1040,16 +1027,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1044 "Python/generated_cases.c.h" + #line 1031 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 761 "Python/bytecodes.c" + #line 758 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1051 "Python/generated_cases.c.h" + #line 1038 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 766 "Python/bytecodes.c" + #line 763 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1062,7 +1049,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1066 "Python/generated_cases.c.h" + #line 1053 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1070,7 +1057,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 781 "Python/bytecodes.c" + #line 778 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1113,7 +1100,7 @@ Py_DECREF(next_iter); } } - #line 1117 "Python/generated_cases.c.h" + #line 1104 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; DISPATCH(); @@ -1122,16 +1109,16 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 826 "Python/bytecodes.c" + #line 823 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1133 "Python/generated_cases.c.h" + #line 1120 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 833 "Python/bytecodes.c" + #line 830 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1148,7 +1135,7 @@ } if (iter == NULL) goto pop_1_error; - #line 1152 "Python/generated_cases.c.h" + #line 1139 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1159,7 +1146,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 857 "Python/bytecodes.c" + #line 854 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1206,7 +1193,7 @@ } } Py_DECREF(v); - #line 1210 "Python/generated_cases.c.h" + #line 1197 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1215,7 +1202,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 906 "Python/bytecodes.c" + #line 903 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1231,12 +1218,12 @@ tstate->exc_info = &gen->gi_exc_state; SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1235 "Python/generated_cases.c.h" + #line 1222 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 924 "Python/bytecodes.c" + #line 921 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1254,12 +1241,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1258 "Python/generated_cases.c.h" + #line 1245 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 944 "Python/bytecodes.c" + #line 941 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1276,15 +1263,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1280 "Python/generated_cases.c.h" + #line 1267 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 963 "Python/bytecodes.c" + #line 960 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1288 "Python/generated_cases.c.h" + #line 1275 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1292,7 +1279,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 968 "Python/bytecodes.c" + #line 965 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1310,26 +1297,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1314 "Python/generated_cases.c.h" + #line 1301 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 988 "Python/bytecodes.c" + #line 985 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1323 "Python/generated_cases.c.h" + #line 1310 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 991 "Python/bytecodes.c" + #line 988 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1333 "Python/generated_cases.c.h" + #line 1320 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1340,23 +1327,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1000 "Python/bytecodes.c" + #line 997 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1349 "Python/generated_cases.c.h" + #line 1336 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1005 "Python/bytecodes.c" + #line 1002 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1360 "Python/generated_cases.c.h" + #line 1347 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1365,9 +1352,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1014 "Python/bytecodes.c" + #line 1011 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1371 "Python/generated_cases.c.h" + #line 1358 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1375,7 +1362,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1018 "Python/bytecodes.c" + #line 1015 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1397,7 +1384,7 @@ if (true) goto error; } } - #line 1401 "Python/generated_cases.c.h" + #line 1388 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1405,33 +1392,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1043 "Python/bytecodes.c" + #line 1040 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1416 "Python/generated_cases.c.h" + #line 1403 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1050 "Python/bytecodes.c" + #line 1047 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1425 "Python/generated_cases.c.h" + #line 1412 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1057 "Python/bytecodes.c" + #line 1054 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1429 "Python/generated_cases.c.h" + #line 1416 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1061 "Python/bytecodes.c" + #line 1058 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1448,7 +1435,7 @@ name); goto error; } - #line 1452 "Python/generated_cases.c.h" + #line 1439 "Python/generated_cases.c.h" DISPATCH(); } @@ -1456,7 +1443,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1087 "Python/bytecodes.c" + #line 1084 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1469,11 +1456,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1473 "Python/generated_cases.c.h" + #line 1460 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1100 "Python/bytecodes.c" + #line 1097 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1477 "Python/generated_cases.c.h" + #line 1464 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1483,14 +1470,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1104 "Python/bytecodes.c" + #line 1101 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1494 "Python/generated_cases.c.h" + #line 1481 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1501,7 +1488,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1114 "Python/bytecodes.c" + #line 1111 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1509,7 +1496,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1513 "Python/generated_cases.c.h" + #line 1500 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1520,7 +1507,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1125 "Python/bytecodes.c" + #line 1122 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1528,7 +1515,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1532 "Python/generated_cases.c.h" + #line 1519 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1538,15 +1525,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1136 "Python/bytecodes.c" + #line 1133 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1546 "Python/generated_cases.c.h" + #line 1533 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1140 "Python/bytecodes.c" + #line 1137 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1550 "Python/generated_cases.c.h" + #line 1537 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1557,7 +1544,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1151 "Python/bytecodes.c" + #line 1148 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1573,12 +1560,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1577 "Python/generated_cases.c.h" + #line 1564 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1167 "Python/bytecodes.c" + #line 1164 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1582 "Python/generated_cases.c.h" + #line 1569 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1586,34 +1573,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1171 "Python/bytecodes.c" + #line 1168 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1593 "Python/generated_cases.c.h" + #line 1580 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1174 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1597 "Python/generated_cases.c.h" + #line 1584 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1178 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1607 "Python/generated_cases.c.h" + #line 1594 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1181 "Python/bytecodes.c" + #line 1178 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1611 "Python/generated_cases.c.h" + #line 1598 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1185 "Python/bytecodes.c" + #line 1182 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1625,7 +1612,7 @@ } goto error; } - #line 1629 "Python/generated_cases.c.h" + #line 1616 "Python/generated_cases.c.h" DISPATCH(); } @@ -1633,7 +1620,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1641,7 +1628,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1645 "Python/generated_cases.c.h" + #line 1632 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1653,7 +1640,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1199 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1661,13 +1648,13 @@ if (true) goto error; } Py_INCREF(locals); - #line 1665 "Python/generated_cases.c.h" + #line 1652 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" + #line 1208 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1724,7 +1711,7 @@ } } } - #line 1728 "Python/generated_cases.c.h" + #line 1715 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1737,7 +1724,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1211 "Python/bytecodes.c" + #line 1208 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1794,7 +1781,7 @@ } } } - #line 1798 "Python/generated_cases.c.h" + #line 1785 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1806,7 +1793,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1280 "Python/bytecodes.c" + #line 1277 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1858,7 +1845,7 @@ } } null = NULL; - #line 1862 "Python/generated_cases.c.h" + #line 1849 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1872,7 +1859,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1334 "Python/bytecodes.c" + #line 1331 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1883,7 +1870,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1887 "Python/generated_cases.c.h" + #line 1874 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1898,7 +1885,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1347 "Python/bytecodes.c" + #line 1344 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1913,7 +1900,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1917 "Python/generated_cases.c.h" + #line 1904 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1923,16 +1910,16 @@ } TARGET(DELETE_FAST) { - #line 1364 "Python/bytecodes.c" + #line 1361 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1931 "Python/generated_cases.c.h" + #line 1918 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1370 "Python/bytecodes.c" + #line 1367 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1941,12 +1928,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1945 "Python/generated_cases.c.h" + #line 1932 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1381 "Python/bytecodes.c" + #line 1378 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1957,14 +1944,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1961 "Python/generated_cases.c.h" + #line 1948 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1394 "Python/bytecodes.c" + #line 1391 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -1999,14 +1986,14 @@ } Py_INCREF(value); } - #line 2003 "Python/generated_cases.c.h" + #line 1990 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1431 "Python/bytecodes.c" + #line 1428 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2014,7 +2001,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2018 "Python/generated_cases.c.h" + #line 2005 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2022,18 +2009,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1441 "Python/bytecodes.c" + #line 1438 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2031 "Python/generated_cases.c.h" + #line 2018 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1448 "Python/bytecodes.c" + #line 1445 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2044,22 +2031,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2048 "Python/generated_cases.c.h" + #line 2035 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1461 "Python/bytecodes.c" + #line 1458 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2057 "Python/generated_cases.c.h" + #line 2044 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1463 "Python/bytecodes.c" + #line 1460 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2063 "Python/generated_cases.c.h" + #line 2050 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2069,10 +2056,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1467 "Python/bytecodes.c" + #line 1464 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2076 "Python/generated_cases.c.h" + #line 2063 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2082,10 +2069,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1472 "Python/bytecodes.c" + #line 1469 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2089 "Python/generated_cases.c.h" + #line 2076 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2095,7 +2082,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1477 "Python/bytecodes.c" + #line 1474 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2106,13 +2093,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2110 "Python/generated_cases.c.h" + #line 2097 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1488 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2116 "Python/generated_cases.c.h" + #line 2103 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2121,13 +2108,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1495 "Python/bytecodes.c" + #line 1492 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2127 "Python/generated_cases.c.h" + #line 2114 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1497 "Python/bytecodes.c" + #line 1494 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2131 "Python/generated_cases.c.h" + #line 2118 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2135,7 +2122,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1501 "Python/bytecodes.c" + #line 1498 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2150,7 +2137,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2154 "Python/generated_cases.c.h" + #line 2141 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2160,7 +2147,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1518 "Python/bytecodes.c" + #line 1515 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2168,13 +2155,13 @@ if (map == NULL) goto error; - #line 2172 "Python/generated_cases.c.h" + #line 2159 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1526 "Python/bytecodes.c" + #line 1523 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2178 "Python/generated_cases.c.h" + #line 2165 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2182,7 +2169,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1530 "Python/bytecodes.c" + #line 1527 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2222,7 +2209,7 @@ Py_DECREF(ann_dict); } } - #line 2226 "Python/generated_cases.c.h" + #line 2213 "Python/generated_cases.c.h" DISPATCH(); } @@ -2230,7 +2217,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1572 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2240,14 +2227,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2244 "Python/generated_cases.c.h" + #line 2231 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1582 "Python/bytecodes.c" + #line 1579 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2251 "Python/generated_cases.c.h" + #line 2238 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2255,7 +2242,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1586 "Python/bytecodes.c" + #line 1583 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2263,12 +2250,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2267 "Python/generated_cases.c.h" + #line 2254 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1594 "Python/bytecodes.c" + #line 1591 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2272 "Python/generated_cases.c.h" + #line 2259 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2276,17 +2263,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1600 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2285 "Python/generated_cases.c.h" + #line 2272 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1605 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2290 "Python/generated_cases.c.h" + #line 2277 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2295,25 +2282,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1611 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2305 "Python/generated_cases.c.h" + #line 2292 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1619 "Python/bytecodes.c" + #line 1616 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2317 "Python/generated_cases.c.h" + #line 2304 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2324,7 +2311,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1633 "Python/bytecodes.c" + #line 1630 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2366,16 +2353,16 @@ } } } - #line 2370 "Python/generated_cases.c.h" + #line 2357 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1675 "Python/bytecodes.c" + #line 1672 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2379 "Python/generated_cases.c.h" + #line 2366 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2390,20 +2377,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1694 "Python/bytecodes.c" + #line 1691 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2401 "Python/generated_cases.c.h" + #line 2388 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1701 "Python/bytecodes.c" + #line 1698 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2407 "Python/generated_cases.c.h" + #line 2394 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2418,7 +2405,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1702 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2441,7 +2428,7 @@ res = res2; res2 = NULL; } - #line 2445 "Python/generated_cases.c.h" + #line 2432 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2455,7 +2442,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1744 "Python/bytecodes.c" + #line 1741 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2489,9 +2476,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2493 "Python/generated_cases.c.h" + #line 2480 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1778 "Python/bytecodes.c" + #line 1775 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2500,12 +2487,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2504 "Python/generated_cases.c.h" + #line 2491 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1787 "Python/bytecodes.c" + #line 1784 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2509 "Python/generated_cases.c.h" + #line 2496 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2519,7 +2506,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1796 "Python/bytecodes.c" + #line 1793 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2532,7 +2519,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2536 "Python/generated_cases.c.h" + #line 2523 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2547,7 +2534,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1812 "Python/bytecodes.c" + #line 1809 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2560,7 +2547,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2564 "Python/generated_cases.c.h" + #line 2551 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2575,7 +2562,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1828 "Python/bytecodes.c" + #line 1825 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2602,7 +2589,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2606 "Python/generated_cases.c.h" + #line 2593 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2617,7 +2604,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1858 "Python/bytecodes.c" + #line 1855 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2627,7 +2614,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2631 "Python/generated_cases.c.h" + #line 2618 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2642,7 +2629,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1871 "Python/bytecodes.c" + #line 1868 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2654,7 +2641,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2658 "Python/generated_cases.c.h" + #line 2645 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2668,7 +2655,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1886 "Python/bytecodes.c" + #line 1883 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2692,7 +2679,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2696 "Python/generated_cases.c.h" + #line 2683 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2700,7 +2687,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1912 "Python/bytecodes.c" + #line 1909 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2726,7 +2713,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2730 "Python/generated_cases.c.h" + #line 2717 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2734,7 +2721,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1940 "Python/bytecodes.c" + #line 1937 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2752,7 +2739,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2756 "Python/generated_cases.c.h" + #line 2743 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2763,7 +2750,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1960 "Python/bytecodes.c" + #line 1957 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2802,7 +2789,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2806 "Python/generated_cases.c.h" + #line 2793 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2813,7 +2800,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2001 "Python/bytecodes.c" + #line 1998 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2823,7 +2810,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2827 "Python/generated_cases.c.h" + #line 2814 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2835,7 +2822,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2020 "Python/bytecodes.c" + #line 2017 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2848,12 +2835,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2852 "Python/generated_cases.c.h" + #line 2839 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2033 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2857 "Python/generated_cases.c.h" + #line 2844 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2864,7 +2851,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2037 "Python/bytecodes.c" + #line 2034 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2875,7 +2862,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2879 "Python/generated_cases.c.h" + #line 2866 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2886,7 +2873,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2051 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2901,7 +2888,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2905 "Python/generated_cases.c.h" + #line 2892 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2912,7 +2899,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2069 "Python/bytecodes.c" + #line 2066 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2924,7 +2911,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2928 "Python/generated_cases.c.h" + #line 2915 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2935,14 +2922,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2083 "Python/bytecodes.c" + #line 2080 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2941 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2085 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2946 "Python/generated_cases.c.h" + #line 2933 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2952,15 +2939,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2089 "Python/bytecodes.c" + #line 2086 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2958 "Python/generated_cases.c.h" + #line 2945 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2091 "Python/bytecodes.c" + #line 2088 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2964 "Python/generated_cases.c.h" + #line 2951 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2971,12 +2958,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2096 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2977 "Python/generated_cases.c.h" + #line 2964 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2098 "Python/bytecodes.c" + #line 2095 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2984,10 +2971,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2988 "Python/generated_cases.c.h" + #line 2975 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2106 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2996,7 +2983,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3000 "Python/generated_cases.c.h" + #line 2987 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3006,21 +2993,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2117 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3013 "Python/generated_cases.c.h" + #line 3000 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2120 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3020 "Python/generated_cases.c.h" + #line 3007 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2125 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3024 "Python/generated_cases.c.h" + #line 3011 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3029,15 +3016,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2129 "Python/bytecodes.c" + #line 2126 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3036 "Python/generated_cases.c.h" + #line 3023 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2132 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3041 "Python/generated_cases.c.h" + #line 3028 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3046,25 +3033,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2136 "Python/bytecodes.c" + #line 2133 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3054 "Python/generated_cases.c.h" + #line 3041 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2142 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" JUMPBY(oparg); - #line 3063 "Python/generated_cases.c.h" + #line 3050 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2146 "Python/bytecodes.c" + #line 2143 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3082,13 +3069,13 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3086 "Python/generated_cases.c.h" + #line 3073 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2177 "Python/bytecodes.c" + #line 2174 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); @@ -3098,20 +3085,20 @@ goto resume_with_error; } goto resume_frame; - #line 3102 "Python/generated_cases.c.h" + #line 3089 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2189 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3113 "Python/generated_cases.c.h" + #line 3100 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2195 "Python/bytecodes.c" + #line 2192 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3119,22 +3106,22 @@ if (err < 0) goto pop_1_error; } } - #line 3123 "Python/generated_cases.c.h" + #line 3110 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2205 "Python/bytecodes.c" + #line 2202 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3136 "Python/generated_cases.c.h" + #line 3123 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2211 "Python/bytecodes.c" + #line 2208 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3142,63 +3129,63 @@ if (err < 0) goto pop_1_error; } } - #line 3146 "Python/generated_cases.c.h" + #line 3133 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2221 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3155 "Python/generated_cases.c.h" + #line 3142 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2223 "Python/bytecodes.c" + #line 2220 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3160 "Python/generated_cases.c.h" + #line 3147 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2228 "Python/bytecodes.c" + #line 2225 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3172 "Python/generated_cases.c.h" + #line 3159 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2233 "Python/bytecodes.c" + #line 2230 "Python/bytecodes.c" } - #line 3176 "Python/generated_cases.c.h" + #line 3163 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2237 "Python/bytecodes.c" + #line 2234 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3189 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2246 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3202 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3209,16 +3196,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2254 "Python/bytecodes.c" + #line 2251 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3218 "Python/generated_cases.c.h" + #line 3205 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2259 "Python/bytecodes.c" + #line 2256 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3226,7 +3213,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3230 "Python/generated_cases.c.h" + #line 3217 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3235,10 +3222,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2269 "Python/bytecodes.c" + #line 2266 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3242 "Python/generated_cases.c.h" + #line 3229 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3247,10 +3234,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2274 "Python/bytecodes.c" + #line 2271 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3254 "Python/generated_cases.c.h" + #line 3241 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3260,11 +3247,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2279 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3268 "Python/generated_cases.c.h" + #line 3255 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3273,14 +3260,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2285 "Python/bytecodes.c" + #line 2282 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3280 "Python/generated_cases.c.h" + #line 3267 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2288 "Python/bytecodes.c" + #line 2285 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3284 "Python/generated_cases.c.h" + #line 3271 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3288,7 +3275,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2292 "Python/bytecodes.c" + #line 2289 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3311,11 +3298,11 @@ if (iter == NULL) { goto error; } - #line 3315 "Python/generated_cases.c.h" + #line 3302 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2315 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" } - #line 3319 "Python/generated_cases.c.h" + #line 3306 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3325,7 +3312,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2333 "Python/bytecodes.c" + #line 2330 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3357,7 +3344,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3361 "Python/generated_cases.c.h" + #line 3348 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3365,7 +3352,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2367 "Python/bytecodes.c" + #line 2364 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3391,14 +3378,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3395 "Python/generated_cases.c.h" + #line 3382 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2395 "Python/bytecodes.c" + #line 2392 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3419,7 +3406,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3423 "Python/generated_cases.c.h" + #line 3410 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3429,7 +3416,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2418 "Python/bytecodes.c" + #line 2415 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3450,7 +3437,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3454 "Python/generated_cases.c.h" + #line 3441 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3460,7 +3447,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2441 "Python/bytecodes.c" + #line 2438 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3479,7 +3466,7 @@ if (next == NULL) { goto error; } - #line 3483 "Python/generated_cases.c.h" + #line 3470 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3488,7 +3475,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2462 "Python/bytecodes.c" + #line 2459 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3504,14 +3491,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3508 "Python/generated_cases.c.h" + #line 3495 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2480 "Python/bytecodes.c" + #line 2477 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3534,16 +3521,16 @@ Py_DECREF(enter); goto error; } - #line 3538 "Python/generated_cases.c.h" + #line 3525 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2503 "Python/bytecodes.c" + #line 2500 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3547 "Python/generated_cases.c.h" + #line 3534 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3554,7 +3541,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2512 "Python/bytecodes.c" + #line 2509 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3580,16 +3567,16 @@ Py_DECREF(enter); goto error; } - #line 3584 "Python/generated_cases.c.h" + #line 3571 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2538 "Python/bytecodes.c" + #line 2535 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3593 "Python/generated_cases.c.h" + #line 3580 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3601,7 +3588,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2547 "Python/bytecodes.c" + #line 2544 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3622,7 +3609,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3626 "Python/generated_cases.c.h" + #line 3613 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3631,7 +3618,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2586 "Python/bytecodes.c" + #line 2583 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3641,7 +3628,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3645 "Python/generated_cases.c.h" + #line 3632 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3655,7 +3642,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2598 "Python/bytecodes.c" + #line 2595 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3672,7 +3659,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3676 "Python/generated_cases.c.h" + #line 3663 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3686,7 +3673,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2617 "Python/bytecodes.c" + #line 2614 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3696,7 +3683,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3700 "Python/generated_cases.c.h" + #line 3687 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3710,7 +3697,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2629 "Python/bytecodes.c" + #line 2626 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3724,7 +3711,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3728 "Python/generated_cases.c.h" + #line 3715 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3733,16 +3720,16 @@ } TARGET(KW_NAMES) { - #line 2645 "Python/bytecodes.c" + #line 2642 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3741 "Python/generated_cases.c.h" + #line 3728 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2651 "Python/bytecodes.c" + #line 2648 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3755,7 +3742,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3759 "Python/generated_cases.c.h" + #line 3746 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3765,7 +3752,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2697 "Python/bytecodes.c" + #line 2694 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3847,7 +3834,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3851 "Python/generated_cases.c.h" + #line 3838 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3859,7 +3846,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2785 "Python/bytecodes.c" + #line 2782 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3869,7 +3856,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3873 "Python/generated_cases.c.h" + #line 3860 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3878,7 +3865,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2797 "Python/bytecodes.c" + #line 2794 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3904,7 +3891,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3908 "Python/generated_cases.c.h" + #line 3895 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3912,7 +3899,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2825 "Python/bytecodes.c" + #line 2822 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3948,7 +3935,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3952 "Python/generated_cases.c.h" + #line 3939 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3956,7 +3943,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2863 "Python/bytecodes.c" + #line 2860 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3966,7 +3953,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3970 "Python/generated_cases.c.h" + #line 3957 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3979,7 +3966,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2875 "Python/bytecodes.c" + #line 2872 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3990,7 +3977,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3994 "Python/generated_cases.c.h" + #line 3981 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4004,7 +3991,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2889 "Python/bytecodes.c" + #line 2886 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4015,7 +4002,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4019 "Python/generated_cases.c.h" + #line 4006 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4028,7 +4015,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2903 "Python/bytecodes.c" + #line 2900 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4078,12 +4065,12 @@ frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); goto start_frame; - #line 4082 "Python/generated_cases.c.h" + #line 4069 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2955 "Python/bytecodes.c" + #line 2952 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4091,7 +4078,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4095 "Python/generated_cases.c.h" + #line 4082 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4101,7 +4088,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2965 "Python/bytecodes.c" + #line 2962 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4123,7 +4110,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4127 "Python/generated_cases.c.h" + #line 4114 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4137,7 +4124,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 2987 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4165,7 +4152,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4169 "Python/generated_cases.c.h" + #line 4156 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4179,7 +4166,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3021 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4211,7 +4198,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4215 "Python/generated_cases.c.h" + #line 4202 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4225,7 +4212,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3056 "Python/bytecodes.c" + #line 3053 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4257,7 +4244,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4261 "Python/generated_cases.c.h" + #line 4248 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4271,7 +4258,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3091 "Python/bytecodes.c" + #line 3088 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4296,7 +4283,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4300 "Python/generated_cases.c.h" + #line 4287 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4309,7 +4296,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3118 "Python/bytecodes.c" + #line 3115 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4336,7 +4323,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4340 "Python/generated_cases.c.h" + #line 4327 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4348,7 +4335,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3148 "Python/bytecodes.c" + #line 3145 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4366,14 +4353,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4370 "Python/generated_cases.c.h" + #line 4357 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3168 "Python/bytecodes.c" + #line 3165 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4404,7 +4391,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4408 "Python/generated_cases.c.h" + #line 4395 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4417,7 +4404,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3202 "Python/bytecodes.c" + #line 3199 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4446,7 +4433,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4450 "Python/generated_cases.c.h" + #line 4437 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4459,7 +4446,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3234 "Python/bytecodes.c" + #line 3231 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4488,7 +4475,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4492 "Python/generated_cases.c.h" + #line 4479 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4501,7 +4488,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3266 "Python/bytecodes.c" + #line 3263 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4529,7 +4516,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4533 "Python/generated_cases.c.h" + #line 4520 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4539,9 +4526,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3297 "Python/bytecodes.c" + #line 3294 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4545 "Python/generated_cases.c.h" + #line 4532 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4550,7 +4537,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3301 "Python/bytecodes.c" + #line 3298 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4612,14 +4599,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4616 "Python/generated_cases.c.h" + #line 4603 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3363 "Python/bytecodes.c" + #line 3360 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4623 "Python/generated_cases.c.h" + #line 4610 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4630,7 +4617,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3369 "Python/bytecodes.c" + #line 3366 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4642,7 +4629,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4646 "Python/generated_cases.c.h" + #line 4633 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4650,7 +4637,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3383 "Python/bytecodes.c" + #line 3380 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4675,14 +4662,14 @@ default: Py_UNREACHABLE(); } - #line 4679 "Python/generated_cases.c.h" + #line 4666 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3410 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4703,7 +4690,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4707 "Python/generated_cases.c.h" + #line 4694 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4711,15 +4698,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3433 "Python/bytecodes.c" + #line 3430 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4717 "Python/generated_cases.c.h" + #line 4704 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3435 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4723 "Python/generated_cases.c.h" + #line 4710 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4729,14 +4716,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3439 "Python/bytecodes.c" + #line 3436 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4740 "Python/generated_cases.c.h" + #line 4727 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4744,7 +4731,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3448 "Python/bytecodes.c" + #line 3445 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4755,7 +4742,7 @@ else { res = value; } - #line 4759 "Python/generated_cases.c.h" + #line 4746 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4764,12 +4751,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3461 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4773 "Python/generated_cases.c.h" + #line 4760 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4778,10 +4765,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3468 "Python/bytecodes.c" + #line 3465 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4785 "Python/generated_cases.c.h" + #line 4772 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4793,7 +4780,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3473 "Python/bytecodes.c" + #line 3470 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4808,12 +4795,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4812 "Python/generated_cases.c.h" + #line 4799 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3488 "Python/bytecodes.c" + #line 3485 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4817 "Python/generated_cases.c.h" + #line 4804 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4823,16 +4810,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3493 "Python/bytecodes.c" + #line 3490 "Python/bytecodes.c" assert(oparg >= 2); - #line 4829 "Python/generated_cases.c.h" + #line 4816 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3497 "Python/bytecodes.c" + #line 3494 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4844,26 +4831,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4848 "Python/generated_cases.c.h" + #line 4835 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3511 "Python/bytecodes.c" + #line 3508 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4854 "Python/generated_cases.c.h" + #line 4841 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3515 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4861 "Python/generated_cases.c.h" + #line 4848 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3520 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4872,12 +4859,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4876 "Python/generated_cases.c.h" + #line 4863 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3531 "Python/bytecodes.c" + #line 3528 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4886,12 +4873,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4890 "Python/generated_cases.c.h" + #line 4877 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3542 "Python/bytecodes.c" + #line 3539 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4903,12 +4890,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4907 "Python/generated_cases.c.h" + #line 4894 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3556 "Python/bytecodes.c" + #line 3553 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4920,30 +4907,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4924 "Python/generated_cases.c.h" + #line 4911 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3570 "Python/bytecodes.c" + #line 3567 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4935 "Python/generated_cases.c.h" + #line 4922 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3578 "Python/bytecodes.c" + #line 3575 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4942 "Python/generated_cases.c.h" + #line 4929 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3583 "Python/bytecodes.c" + #line 3580 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4949 "Python/generated_cases.c.h" + #line 4936 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index cfdc09294e9dee..991006ceb182a6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -5,6 +5,7 @@ #define IS_PSEUDO_INSTR(OP) \ + ((OP) == LOAD_CLOSURE) || \ ((OP) == STORE_FAST_MAYBE_NULL) || \ ((OP) == LOAD_SUPER_METHOD) || \ ((OP) == LOAD_ZERO_SUPER_METHOD) || \ diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 781d72fa7f5333..8561d9d4a3638e 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -135,7 +135,7 @@ static void *opcode_targets[256] = { &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, - &&TARGET_LOAD_CLOSURE, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, @@ -147,26 +147,26 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_LEN, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_CALL_NO_KW_LEN, &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LIST_APPEND, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_CONVERT_VALUE, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT, + &&_unknown_opcode, &&TARGET_LOAD_FAST_LOAD_FAST, &&TARGET_STORE_FAST_LOAD_FAST, &&TARGET_STORE_FAST_STORE_FAST, From 6e9f83d9aee34192de5d0ef7285be23514911ccd Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 29 Jun 2023 13:02:25 -0700 Subject: [PATCH 185/446] GH-106250: Support insts using one cache entry and no oparg (GH-106252) --- Tools/cases_generator/generate_cases.py | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 7c99e3b929b463..ff88b63d3bdd80 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -602,6 +602,9 @@ def write_body(self, out: Formatter) -> None: out.assign(var, oeffect) +MacroParts = list[Component | parser.CacheEffect] + + @dataclasses.dataclass class MacroInstruction: """A macro instruction.""" @@ -613,7 +616,7 @@ class MacroInstruction: instr_fmt: str instr_flags: InstructionFlags macro: parser.Macro - parts: list[Component | parser.CacheEffect] + parts: MacroParts cache_offset: int predicted: bool = False @@ -906,7 +909,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: components = self.check_macro_components(macro) stack, initial_sp = self.stack_analysis(components) sp = initial_sp - parts: list[Component | parser.CacheEffect] = [] + parts: MacroParts = [] flags = InstructionFlags.newEmpty() offset = 0 for component in components: @@ -1253,17 +1256,14 @@ def write_metadata(self) -> None: pass case parser.InstDef(name=name): instr = self.instrs[name] - # Since an 'op' is not a bytecode, it has no expansion - if instr.kind != "op" and instr.is_viable_uop(): - # Double check there aren't any used cache effects. - # If this fails, see write_macro_expansions(). - assert not instr.active_caches, (instr.name, instr.cache_effects) - self.out.emit( - f"[{name}] = " - f"{{ .nuops = 1, .uops = {{ {{ {name}, 0, 0 }} }} }}," - ) + # Since an 'op' is not a bytecode, it has no expansion; but 'inst' is + if instr.kind == "inst" and instr.is_viable_uop(): + # Construct a dummy Component -- input/output mappings are not used + part = Component(instr, [], [], instr.active_caches) + self.write_macro_expansions(instr.name, [part]) case parser.Macro(): - self.write_macro_expansions(self.macro_instrs[thing.name]) + mac = self.macro_instrs[thing.name] + self.write_macro_expansions(mac.name, mac.parts) case parser.Pseudo(): pass case _: @@ -1328,29 +1328,29 @@ def add(name: str) -> None: if instr.kind == "op" and instr.is_viable_uop(): add(instr.name) - def write_macro_expansions(self, mac: MacroInstruction) -> None: + def write_macro_expansions(self, name: str, parts: MacroParts) -> None: """Write the macro expansions for a macro-instruction.""" # TODO: Refactor to share code with write_cody(), is_viaible_uop(), etc. offset = 0 # Cache effect offset expansions: list[tuple[str, int, int]] = [] # [(name, size, offset), ...] - for part in mac.parts: + for part in parts: if isinstance(part, Component): # All component instructions must be viable uops if not part.instr.is_viable_uop(): - print(f"NOTE: Part {part.instr.name} of {mac.name} is not a viable uop") + print(f"NOTE: Part {part.instr.name} of {name} is not a viable uop") return if part.instr.instr_flags.HAS_ARG_FLAG or not part.active_caches: size, offset = 0, 0 else: # If this assert triggers, is_viable_uops() lied - assert len(part.active_caches) == 1, (mac.name, part.instr.name) + assert len(part.active_caches) == 1, (name, part.instr.name) cache = part.active_caches[0] size, offset = cache.effect.size, cache.offset expansions.append((part.instr.name, size, offset)) - assert len(expansions) > 0, f"Macro {mac.name} has empty expansion?!" + assert len(expansions) > 0, f"Macro {name} has empty expansion?!" pieces = [f"{{ {name}, {size}, {offset} }}" for name, size, offset in expansions] self.out.emit( - f"[{mac.name}] = " + f"[{name}] = " f"{{ .nuops = {len(expansions)}, .uops = {{ {', '.join(pieces)} }} }}," ) From 7b2d94d87513967b357c658c6e7e1b8c8d02487d Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 29 Jun 2023 13:49:54 -0700 Subject: [PATCH 186/446] GH-106008: Make implicit boolean conversions explicit (GH-106003) --- .gitattributes | 3 +- Doc/library/dis.rst | 23 +- Include/internal/pycore_code.h | 8 + Include/internal/pycore_opcode.h | 137 +- Include/opcode.h | 127 +- Lib/_opcode_metadata.py | 8 + Lib/dis.py | 4 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 10 +- Lib/test/test_compiler_codegen.py | 1 + Lib/test/test_dis.py | 237 ++-- ...-06-22-17-37-35.gh-issue-106003.2Vc_Tw.rst | 5 + Python/bytecodes.c | 144 ++- Python/compile.c | 21 +- Python/executor_cases.c.h | 572 +++++---- Python/flowgraph.c | 149 ++- Python/generated_cases.c.h | 1136 +++++++++-------- Python/opcode_metadata.h | 43 +- Python/opcode_targets.h | 122 +- Python/specialize.c | 113 +- 20 files changed, 1721 insertions(+), 1145 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-22-17-37-35.gh-issue-106003.2Vc_Tw.rst diff --git a/.gitattributes b/.gitattributes index a2ff14c66323e2..5e4ce963b63e5c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -85,8 +85,9 @@ Parser/parser.c generated Parser/token.c generated Programs/test_frozenmain.h generated Python/Python-ast.c generated -Python/generated_cases.c.h generated Python/executor_cases.c.h generated +Python/generated_cases.c.h generated +Python/opcode_metadata.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 63336bb9e08ead..099b6410f165ed 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -529,6 +529,9 @@ result back on the stack. Implements ``STACK[-1] = not STACK[-1]``. + .. versionchanged:: 3.13 + This instruction now requires an exact :class:`bool` operand. + .. opcode:: UNARY_INVERT @@ -548,6 +551,13 @@ result back on the stack. .. versionadded:: 3.5 +.. opcode:: TO_BOOL + + Implements ``STACK[-1] = bool(STACK[-1])``. + + .. versionadded:: 3.13 + + **Binary and in-place operations** Binary operations remove the top two items from the stack (``STACK[-1]`` and @@ -1127,7 +1137,12 @@ iterations of the loop. .. opcode:: COMPARE_OP (opname) Performs a Boolean operation. The operation name can be found in - ``cmp_op[opname]``. + ``cmp_op[opname >> 5]``. If the fifth-lowest bit of ``opname`` is set + (``opname & 16``), the result should be coerced to ``bool``. + + .. versionchanged:: 3.13 + The fifth-lowest bit of the oparg now indicates a forced conversion to + :class:`bool`. .. opcode:: IS_OP (invert) @@ -1191,6 +1206,9 @@ iterations of the loop. .. versionchanged:: 3.12 This is no longer a pseudo-instruction. + .. versionchanged:: 3.13 + This instruction now requires an exact :class:`bool` operand. + .. opcode:: POP_JUMP_IF_FALSE (delta) If ``STACK[-1]`` is false, increments the bytecode counter by *delta*. @@ -1204,6 +1222,9 @@ iterations of the loop. .. versionchanged:: 3.12 This is no longer a pseudo-instruction. + .. versionchanged:: 3.13 + This instruction now requires an exact :class:`bool` operand. + .. opcode:: POP_JUMP_IF_NOT_NONE (delta) If ``STACK[-1]`` is not ``None``, increments the bytecode counter by *delta*. diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8755cb371a87c4..d1829eb3245d26 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -101,6 +101,13 @@ typedef struct { #define INLINE_CACHE_ENTRIES_SEND CACHE_ENTRIES(_PySendCache) +typedef struct { + uint16_t counter; + uint16_t version[2]; +} _PyToBoolCache; + +#define INLINE_CACHE_ENTRIES_TO_BOOL CACHE_ENTRIES(_PyToBoolCache) + // Borrowed references to common callables: struct callable_cache { PyObject *isinstance; @@ -246,6 +253,7 @@ extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr); +extern void _Py_Specialize_ToBool(PyObject *value, _Py_CODEUNIT *instr); /* Finalizer function for static codeobjects used in deepfreeze.py */ extern void _PyStaticCode_Fini(PyCodeObject *co); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index bebdedc962403a..428df4ccadbc19 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -19,6 +19,7 @@ extern const uint8_t _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_TABLES const uint8_t _PyOpcode_Caches[256] = { + [TO_BOOL] = 3, [BINARY_SUBSCR] = 1, [STORE_SUBSCR] = 1, [UNPACK_SEQUENCE] = 1, @@ -221,6 +222,13 @@ const uint8_t _PyOpcode_Deopt[256] = { [STORE_SUBSCR_DICT] = STORE_SUBSCR, [STORE_SUBSCR_LIST_INT] = STORE_SUBSCR, [SWAP] = SWAP, + [TO_BOOL] = TO_BOOL, + [TO_BOOL_ALWAYS_TRUE] = TO_BOOL, + [TO_BOOL_BOOL] = TO_BOOL, + [TO_BOOL_INT] = TO_BOOL, + [TO_BOOL_LIST] = TO_BOOL, + [TO_BOOL_NONE] = TO_BOOL, + [TO_BOOL_STR] = TO_BOOL, [UNARY_INVERT] = UNARY_INVERT, [UNARY_NEGATIVE] = UNARY_NEGATIVE, [UNARY_NOT] = UNARY_NOT, @@ -242,49 +250,49 @@ static const char *const _PyOpcode_OpName[268] = { [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", [END_SEND] = "END_SEND", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [TO_BOOL] = "TO_BOOL", + [TO_BOOL_ALWAYS_TRUE] = "TO_BOOL_ALWAYS_TRUE", + [TO_BOOL_BOOL] = "TO_BOOL_BOOL", [NOP] = "NOP", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [TO_BOOL_INT] = "TO_BOOL_INT", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", - [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [TO_BOOL_LIST] = "TO_BOOL_LIST", + [TO_BOOL_NONE] = "TO_BOOL_NONE", [UNARY_INVERT] = "UNARY_INVERT", [EXIT_INIT_CHECK] = "EXIT_INIT_CHECK", [RESERVED] = "RESERVED", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", - [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", - [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", - [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", - [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [TO_BOOL_STR] = "TO_BOOL_STR", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", + [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [MAKE_FUNCTION] = "MAKE_FUNCTION", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [SEND_GEN] = "SEND_GEN", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", + [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", [FORMAT_SIMPLE] = "FORMAT_SIMPLE", [FORMAT_WITH_SPEC] = "FORMAT_WITH_SPEC", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", + [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", + [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [SEND_GEN] = "SEND_GEN", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -292,39 +300,39 @@ static const char *const _PyOpcode_OpName[268] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_SUBSCR] = "STORE_SUBSCR", + [DELETE_SUBSCR] = "DELETE_SUBSCR", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_SUPER_ATTR_ATTR] = "LOAD_SUPER_ATTR_ATTR", [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", - [STORE_SUBSCR] = "STORE_SUBSCR", - [DELETE_SUBSCR] = "DELETE_SUBSCR", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [GET_ITER] = "GET_ITER", - [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [COMPARE_OP_INT] = "COMPARE_OP_INT", - [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", - [RETURN_GENERATOR] = "RETURN_GENERATOR", - [COMPARE_OP_STR] = "COMPARE_OP_STR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", - [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", - [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [FOR_ITER_GEN] = "FOR_ITER_GEN", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [RETURN_VALUE] = "RETURN_VALUE", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [FOR_ITER_LIST] = "FOR_ITER_LIST", [LOAD_LOCALS] = "LOAD_LOCALS", - [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -347,9 +355,9 @@ static const char *const _PyOpcode_OpName[268] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", - [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [FOR_ITER_RANGE] = "FOR_ITER_RANGE", + [FOR_ITER_GEN] = "FOR_ITER_GEN", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -368,11 +376,11 @@ static const char *const _PyOpcode_OpName[268] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [LOAD_DEREF] = "LOAD_DEREF", [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", @@ -384,26 +392,26 @@ static const char *const _PyOpcode_OpName[268] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", - [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", [CONVERT_VALUE] = "CONVERT_VALUE", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT", - [167] = "<167>", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST", [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST", [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST", @@ -414,12 +422,12 @@ static const char *const _PyOpcode_OpName[268] = { [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS", [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF", [SET_FUNCTION_ATTRIBUTE] = "SET_FUNCTION_ATTRIBUTE", - [178] = "<178>", - [179] = "<179>", - [180] = "<180>", - [181] = "<181>", - [182] = "<182>", - [183] = "<183>", + [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -508,13 +516,6 @@ static const char *const _PyOpcode_OpName[268] = { #endif #define EXTRA_CASES \ - case 167: \ - case 178: \ - case 179: \ - case 180: \ - case 181: \ - case 182: \ - case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index 0533ae96688707..6b855bdd99dfa2 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -14,6 +14,7 @@ extern "C" { #define INTERPRETER_EXIT 3 #define END_FOR 4 #define END_SEND 5 +#define TO_BOOL 6 #define NOP 9 #define UNARY_NEGATIVE 11 #define UNARY_NOT 12 @@ -159,66 +160,72 @@ extern "C" { #define STORE_FAST_MAYBE_NULL 266 #define LOAD_CLOSURE 267 #define MAX_PSEUDO_OPCODE 267 -#define BINARY_OP_MULTIPLY_INT 6 -#define BINARY_OP_ADD_INT 7 -#define BINARY_OP_SUBTRACT_INT 8 -#define BINARY_OP_MULTIPLY_FLOAT 10 -#define BINARY_OP_ADD_FLOAT 13 -#define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_ADD_UNICODE 18 -#define BINARY_OP_INPLACE_ADD_UNICODE 19 -#define BINARY_SUBSCR_DICT 20 -#define BINARY_SUBSCR_GETITEM 21 -#define BINARY_SUBSCR_LIST_INT 22 -#define BINARY_SUBSCR_TUPLE_INT 23 -#define STORE_SUBSCR_DICT 28 -#define STORE_SUBSCR_LIST_INT 29 -#define SEND_GEN 34 -#define UNPACK_SEQUENCE_TWO_TUPLE 38 -#define UNPACK_SEQUENCE_TUPLE 39 -#define UNPACK_SEQUENCE_LIST 42 -#define STORE_ATTR_INSTANCE_VALUE 43 -#define STORE_ATTR_SLOT 44 -#define STORE_ATTR_WITH_HINT 45 -#define LOAD_GLOBAL_MODULE 46 -#define LOAD_GLOBAL_BUILTIN 47 -#define LOAD_SUPER_ATTR_ATTR 48 -#define LOAD_SUPER_ATTR_METHOD 56 -#define LOAD_ATTR_INSTANCE_VALUE 57 -#define LOAD_ATTR_MODULE 58 -#define LOAD_ATTR_WITH_HINT 59 -#define LOAD_ATTR_SLOT 62 -#define LOAD_ATTR_CLASS 63 -#define LOAD_ATTR_PROPERTY 64 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 -#define LOAD_ATTR_METHOD_WITH_VALUES 66 -#define LOAD_ATTR_METHOD_NO_DICT 67 -#define LOAD_ATTR_METHOD_LAZY_DICT 70 -#define COMPARE_OP_FLOAT 72 -#define COMPARE_OP_INT 73 -#define COMPARE_OP_STR 76 -#define FOR_ITER_LIST 77 -#define FOR_ITER_TUPLE 78 -#define FOR_ITER_RANGE 79 -#define FOR_ITER_GEN 80 -#define CALL_BOUND_METHOD_EXACT_ARGS 81 -#define CALL_PY_EXACT_ARGS 82 -#define CALL_PY_WITH_DEFAULTS 84 -#define CALL_NO_KW_TYPE_1 86 -#define CALL_NO_KW_STR_1 88 -#define CALL_NO_KW_TUPLE_1 111 -#define CALL_BUILTIN_CLASS 112 -#define CALL_NO_KW_BUILTIN_O 113 -#define CALL_NO_KW_BUILTIN_FAST 132 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 136 -#define CALL_NO_KW_LEN 148 -#define CALL_NO_KW_ISINSTANCE 153 -#define CALL_NO_KW_LIST_APPEND 154 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 155 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 159 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 160 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 161 -#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 166 +#define TO_BOOL_ALWAYS_TRUE 7 +#define TO_BOOL_BOOL 8 +#define TO_BOOL_INT 10 +#define TO_BOOL_LIST 13 +#define TO_BOOL_NONE 14 +#define TO_BOOL_STR 18 +#define BINARY_OP_MULTIPLY_INT 19 +#define BINARY_OP_ADD_INT 20 +#define BINARY_OP_SUBTRACT_INT 21 +#define BINARY_OP_MULTIPLY_FLOAT 22 +#define BINARY_OP_ADD_FLOAT 23 +#define BINARY_OP_SUBTRACT_FLOAT 28 +#define BINARY_OP_ADD_UNICODE 29 +#define BINARY_OP_INPLACE_ADD_UNICODE 34 +#define BINARY_SUBSCR_DICT 38 +#define BINARY_SUBSCR_GETITEM 39 +#define BINARY_SUBSCR_LIST_INT 42 +#define BINARY_SUBSCR_TUPLE_INT 43 +#define STORE_SUBSCR_DICT 44 +#define STORE_SUBSCR_LIST_INT 45 +#define SEND_GEN 46 +#define UNPACK_SEQUENCE_TWO_TUPLE 47 +#define UNPACK_SEQUENCE_TUPLE 48 +#define UNPACK_SEQUENCE_LIST 56 +#define STORE_ATTR_INSTANCE_VALUE 57 +#define STORE_ATTR_SLOT 58 +#define STORE_ATTR_WITH_HINT 59 +#define LOAD_GLOBAL_MODULE 62 +#define LOAD_GLOBAL_BUILTIN 63 +#define LOAD_SUPER_ATTR_ATTR 64 +#define LOAD_SUPER_ATTR_METHOD 65 +#define LOAD_ATTR_INSTANCE_VALUE 66 +#define LOAD_ATTR_MODULE 67 +#define LOAD_ATTR_WITH_HINT 70 +#define LOAD_ATTR_SLOT 72 +#define LOAD_ATTR_CLASS 73 +#define LOAD_ATTR_PROPERTY 76 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 77 +#define LOAD_ATTR_METHOD_WITH_VALUES 78 +#define LOAD_ATTR_METHOD_NO_DICT 79 +#define LOAD_ATTR_METHOD_LAZY_DICT 80 +#define COMPARE_OP_FLOAT 81 +#define COMPARE_OP_INT 82 +#define COMPARE_OP_STR 84 +#define FOR_ITER_LIST 86 +#define FOR_ITER_TUPLE 88 +#define FOR_ITER_RANGE 111 +#define FOR_ITER_GEN 112 +#define CALL_BOUND_METHOD_EXACT_ARGS 113 +#define CALL_PY_EXACT_ARGS 132 +#define CALL_PY_WITH_DEFAULTS 136 +#define CALL_NO_KW_TYPE_1 148 +#define CALL_NO_KW_STR_1 153 +#define CALL_NO_KW_TUPLE_1 154 +#define CALL_BUILTIN_CLASS 155 +#define CALL_NO_KW_BUILTIN_O 159 +#define CALL_NO_KW_BUILTIN_FAST 160 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 161 +#define CALL_NO_KW_LEN 166 +#define CALL_NO_KW_ISINSTANCE 167 +#define CALL_NO_KW_LIST_APPEND 178 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 179 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 180 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 181 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 182 +#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 183 #define NB_ADD 0 #define NB_AND 1 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index c0a68256802c37..b0fcd1a6b920f3 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -4,6 +4,14 @@ # Do not edit! _specializations = { + "TO_BOOL": [ + "TO_BOOL_ALWAYS_TRUE", + "TO_BOOL_BOOL", + "TO_BOOL_INT", + "TO_BOOL_LIST", + "TO_BOOL_NONE", + "TO_BOOL_STR", + ], "BINARY_OP": [ "BINARY_OP_MULTIPLY_INT", "BINARY_OP_ADD_INT", diff --git a/Lib/dis.py b/Lib/dis.py index f135a0bc9b4d98..f7a31f2f96b99b 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -572,8 +572,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None, elif deop in haslocal or deop in hasfree: argval, argrepr = _get_name_info(arg, varname_from_oparg) elif deop in hascompare: - argval = cmp_op[arg>>4] + argval = cmp_op[arg >> 5] argrepr = argval + if arg & 16: + argrepr = f"bool({argrepr})" elif deop == CONVERT_VALUE: argval = (None, str, repr, ascii)[arg] argrepr = ('', 'str', 'repr', 'ascii')[arg] diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 8b4ac6ca012045..16a82bef2ba71f 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -452,6 +452,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.13a1 3554 (more efficient bytecodes for f-strings) # Python 3.13a1 3555 (generate specialized opcodes metadata from bytecodes.c) # Python 3.13a1 3556 (Convert LOAD_CLOSURE to a pseudo-op) +# Python 3.13a1 3557 (Make the conversion to boolean in jumps explicit) # Python 3.14 will start with 3600 @@ -468,7 +469,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 = (3556).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3557).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 52c566cd0cabc6..bc885051c6454e 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -87,9 +87,9 @@ def pseudo_op(name, op, real_ops): def_op('POP_TOP', 1) def_op('PUSH_NULL', 2) def_op('INTERPRETER_EXIT', 3) - def_op('END_FOR', 4) def_op('END_SEND', 5) +def_op('TO_BOOL', 6) def_op('NOP', 9) @@ -142,6 +142,7 @@ def pseudo_op(name, op, real_ops): def_op('RETURN_VALUE', 83) def_op('SETUP_ANNOTATIONS', 85) + def_op('LOAD_LOCALS', 87) def_op('POP_EXCEPT', 89) @@ -171,6 +172,7 @@ def pseudo_op(name, op, real_ops): name_op('IMPORT_NAME', 108) # Index in name list name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of words to skip + jrel_op('POP_JUMP_IF_FALSE', 114) jrel_op('POP_JUMP_IF_TRUE', 115) name_op('LOAD_GLOBAL', 116) # Index in name list @@ -209,7 +211,6 @@ def pseudo_op(name, op, real_ops): def_op('CALL_FUNCTION_EX', 142) # Flags def_op('LOAD_FAST_AND_CLEAR', 143) # Local variable number haslocal.append(143) - def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 def_op('LIST_APPEND', 145) @@ -238,7 +239,6 @@ def pseudo_op(name, op, real_ops): hasconst.append(172) def_op('CALL_INTRINSIC_1', 173) def_op('CALL_INTRINSIC_2', 174) - name_op('LOAD_FROM_DICT_OR_GLOBALS', 175) def_op('LOAD_FROM_DICT_OR_DEREF', 176) hasfree.append(176) @@ -404,6 +404,10 @@ def pseudo_op(name, op, real_ops): "JUMP_BACKWARD": { "counter": 1, }, + "TO_BOOL": { + "counter": 1, + "version": 2, + }, } _inline_cache_entries = [ diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py index ea57df9cd2400b..d99bb8c6cd472d 100644 --- a/Lib/test/test_compiler_codegen.py +++ b/Lib/test/test_compiler_codegen.py @@ -18,6 +18,7 @@ def test_if_expression(self): expected = [ ('RESUME', 0, 0), ('LOAD_CONST', 0, 1), + ('TO_BOOL', 0, 1), ('POP_JUMP_IF_FALSE', false_lbl := self.Label(), 1), ('LOAD_CONST', 1, 1), ('JUMP', exit_lbl := self.Label()), diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index ab8026b81fd3d6..8597b8f14ac058 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -46,7 +46,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 40 (==) + COMPARE_OP 72 (==) LOAD_FAST 0 (self) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -56,7 +56,7 @@ def cm(cls, x): RESUME 0 LOAD_FAST 1 LOAD_CONST 1 - COMPARE_OP 40 (==) + COMPARE_OP 72 (==) LOAD_FAST 0 STORE_ATTR 0 RETURN_CONST 0 @@ -67,7 +67,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 40 (==) + COMPARE_OP 72 (==) LOAD_FAST 0 (cls) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -78,7 +78,7 @@ def cm(cls, x): %3d LOAD_FAST 0 (x) LOAD_CONST 1 (1) - COMPARE_OP 40 (==) + COMPARE_OP 72 (==) STORE_FAST 0 (x) RETURN_CONST 0 (None) """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) @@ -488,7 +488,8 @@ def _with(c): %3d >> PUSH_EXC_INFO WITH_EXCEPT_START - POP_JUMP_IF_TRUE 1 (to 42) + TO_BOOL + POP_JUMP_IF_TRUE 1 (to 50) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -567,7 +568,8 @@ async def _asyncwith(c): JUMP_BACKWARD_NO_INTERRUPT 5 (to 90) >> CLEANUP_THROW >> END_SEND - POP_JUMP_IF_TRUE 1 (to 108) + TO_BOOL + POP_JUMP_IF_TRUE 1 (to 116) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -1570,24 +1572,43 @@ def jumpy(): def _stringify_instruction(instr): # Since line numbers and other offsets change a lot for these # test cases, ignore them. - return repr(instr._replace(positions=None)) + return f" {instr._replace(positions=None)!r}," def _prepare_test_cases(): - _instructions = dis.get_instructions(outer, first_line=expected_outer_line) - print('expected_opinfo_outer = [\n ', - ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') - _instructions = dis.get_instructions(outer(), first_line=expected_f_line) - print('expected_opinfo_f = [\n ', - ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') - _instructions = dis.get_instructions(outer()(), first_line=expected_inner_line) - print('expected_opinfo_inner = [\n ', - ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') - _instructions = dis.get_instructions(jumpy, first_line=expected_jumpy_line) - print('expected_opinfo_jumpy = [\n ', - ',\n '.join(map(_stringify_instruction, _instructions)), ',\n]', sep='') - dis.dis(outer) - -#_prepare_test_cases() + ignore = io.StringIO() + with contextlib.redirect_stdout(ignore): + f = outer() + inner = f() + _instructions_outer = dis.get_instructions(outer, first_line=expected_outer_line) + _instructions_f = dis.get_instructions(f, first_line=expected_f_line) + _instructions_inner = dis.get_instructions(inner, first_line=expected_inner_line) + _instructions_jumpy = dis.get_instructions(jumpy, first_line=expected_jumpy_line) + result = "\n".join( + [ + "expected_opinfo_outer = [", + *map(_stringify_instruction, _instructions_outer), + "]", + "", + "expected_opinfo_f = [", + *map(_stringify_instruction, _instructions_f), + "]", + "", + "expected_opinfo_inner = [", + *map(_stringify_instruction, _instructions_inner), + "]", + "", + "expected_opinfo_jumpy = [", + *map(_stringify_instruction, _instructions_jumpy), + "]", + ] + ) + result = result.replace(repr(repr(code_object_f)), "repr(code_object_f)") + result = result.replace(repr(code_object_f), "code_object_f") + result = result.replace(repr(repr(code_object_inner)), "repr(code_object_inner)") + result = result.replace(repr(code_object_inner), "code_object_inner") + print(result) + +# _prepare_test_cases() Instruction = dis.Instruction @@ -1659,7 +1680,6 @@ def _prepare_test_cases(): Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=34, start_offset=34, starts_line=None, is_jump_target=False, positions=None), ] - expected_opinfo_jumpy = [ Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=1, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, start_offset=2, starts_line=3, is_jump_target=False, positions=None), @@ -1674,12 +1694,12 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, start_offset=50, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, start_offset=52, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=54, start_offset=54, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=18, argval='<', argrepr='bool(<)', offset=56, start_offset=56, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=66, argrepr='to 66', offset=60, start_offset=60, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=24, argrepr='to 24', offset=62, start_offset=62, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, start_offset=66, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=68, start_offset=68, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=70, start_offset=70, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=148, argval='>', argrepr='bool(>)', offset=70, start_offset=70, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=2, argval=80, argrepr='to 80', offset=74, start_offset=74, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=28, argval=24, argrepr='to 24', offset=76, start_offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, start_offset=80, starts_line=8, is_jump_target=True, positions=None), @@ -1690,90 +1710,93 @@ def _prepare_test_cases(): Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=98, start_offset=98, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, start_offset=106, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=108, start_offset=108, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=33, argval=178, argrepr='to 178', offset=110, start_offset=110, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=112, start_offset=112, starts_line=12, is_jump_target=True, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=122, start_offset=122, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=124, start_offset=124, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, start_offset=132, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=134, start_offset=134, starts_line=13, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=136, start_offset=136, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=138, start_offset=138, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=142, start_offset=142, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, start_offset=144, starts_line=14, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=146, start_offset=146, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=148, start_offset=148, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=158, argrepr='to 158', offset=152, start_offset=152, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=108, argrepr='to 108', offset=154, start_offset=154, starts_line=15, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=16, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=160, start_offset=160, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=162, start_offset=162, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=170, argrepr='to 170', offset=166, start_offset=166, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=200, argrepr='to 200', offset=168, start_offset=168, starts_line=17, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=170, start_offset=170, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=178, argrepr='to 178', offset=172, start_offset=172, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=112, argrepr='to 112', offset=174, start_offset=174, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=178, start_offset=178, starts_line=19, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=188, start_offset=188, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=190, start_offset=190, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, start_offset=198, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=200, start_offset=200, starts_line=20, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=202, start_offset=202, starts_line=21, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=204, start_offset=204, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=206, start_offset=206, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=210, start_offset=210, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=212, start_offset=212, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=216, start_offset=216, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=218, start_offset=218, starts_line=26, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=228, start_offset=228, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=230, start_offset=230, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=238, start_offset=238, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=240, start_offset=240, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=242, start_offset=242, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=244, start_offset=244, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=246, start_offset=246, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=110, start_offset=110, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=37, argval=194, argrepr='to 194', offset=118, start_offset=118, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=120, start_offset=120, starts_line=12, is_jump_target=True, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=130, start_offset=130, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=132, start_offset=132, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=140, start_offset=140, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=142, start_offset=142, starts_line=13, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=144, start_offset=144, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=146, start_offset=146, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, start_offset=152, starts_line=14, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=154, start_offset=154, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=148, argval='>', argrepr='bool(>)', offset=156, start_offset=156, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=166, argrepr='to 166', offset=160, start_offset=160, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=108, argrepr='to 108', offset=162, start_offset=162, starts_line=15, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=166, start_offset=166, starts_line=16, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=168, start_offset=168, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=18, argval='<', argrepr='bool(<)', offset=170, start_offset=170, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=178, argrepr='to 178', offset=174, start_offset=174, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=19, argval=216, argrepr='to 216', offset=176, start_offset=176, starts_line=17, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=180, start_offset=180, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=2, argval=194, argrepr='to 194', offset=188, start_offset=188, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=37, argval=120, argrepr='to 120', offset=190, start_offset=190, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=194, start_offset=194, starts_line=19, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=20, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=218, start_offset=218, starts_line=21, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=220, start_offset=220, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=222, start_offset=222, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, start_offset=226, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=228, start_offset=228, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=232, start_offset=232, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=234, start_offset=234, starts_line=26, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=244, start_offset=244, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=246, start_offset=246, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=254, start_offset=254, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=256, start_offset=256, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=266, start_offset=266, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=268, start_offset=268, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=276, start_offset=276, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=278, start_offset=278, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=280, start_offset=280, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=282, start_offset=282, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=288, argrepr='to 288', offset=284, start_offset=284, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=286, start_offset=286, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=288, start_offset=288, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=290, start_offset=290, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=256, start_offset=256, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=258, start_offset=258, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=260, start_offset=260, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=262, start_offset=262, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=272, start_offset=272, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=282, start_offset=282, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=284, start_offset=284, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=292, start_offset=292, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=294, start_offset=294, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=256, argrepr='to 256', offset=296, start_offset=296, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=300, start_offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=302, start_offset=302, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=304, start_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, start_offset=306, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=308, start_offset=308, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=15, argval=352, argrepr='to 352', offset=320, start_offset=320, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=322, start_offset=322, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=324, start_offset=324, 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=334, start_offset=334, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=336, start_offset=336, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=48, argval=256, argrepr='to 256', offset=348, start_offset=348, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=352, start_offset=352, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=354, start_offset=354, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=358, start_offset=358, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=362, start_offset=362, 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=372, start_offset=372, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=374, start_offset=374, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=382, start_offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=384, start_offset=384, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=386, start_offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=388, start_offset=388, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=390, start_offset=390, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=294, start_offset=294, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=296, start_offset=296, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=298, start_offset=298, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='TO_BOOL', opcode=6, arg=None, argval=None, argrepr='', offset=300, start_offset=300, 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, start_offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=310, start_offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=272, argrepr='to 272', offset=320, start_offset=320, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=324, start_offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=326, start_offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=328, start_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, start_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, start_offset=332, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=342, start_offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=15, argval=376, argrepr='to 376', offset=344, start_offset=344, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=346, start_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, start_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=358, start_offset=358, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=360, start_offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=368, start_offset=368, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=370, start_offset=370, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=272, argrepr='to 272', offset=372, start_offset=372, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=376, start_offset=376, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=378, start_offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, start_offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=382, start_offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=386, start_offset=386, 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=396, start_offset=396, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=398, start_offset=398, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=406, start_offset=406, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=408, start_offset=408, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=410, start_offset=410, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=412, start_offset=412, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=414, start_offset=414, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-22-17-37-35.gh-issue-106003.2Vc_Tw.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-17-37-35.gh-issue-106003.2Vc_Tw.rst new file mode 100644 index 00000000000000..47143f7eb8f383 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-22-17-37-35.gh-issue-106003.2Vc_Tw.rst @@ -0,0 +1,5 @@ +Add a new :opcode:`TO_BOOL` instruction, which performs boolean conversions +for :opcode:`POP_JUMP_IF_TRUE`, :opcode:`POP_JUMP_IF_FALSE`, and +:opcode:`UNARY_NOT` (which all expect exact :class:`bool` values now). Also, +modify the oparg of :opcode:`COMPARE_OP` to include an optional "boolean +conversion" flag. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1d9664bc27d244..cd23e6624706fa 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -279,15 +279,90 @@ dummy_func( } inst(UNARY_NOT, (value -- res)) { + assert(PyBool_Check(value)); + res = Py_IsFalse(value) ? Py_True : Py_False; + } + + family(to_bool, INLINE_CACHE_ENTRIES_TO_BOOL) = { + TO_BOOL, + TO_BOOL_ALWAYS_TRUE, + TO_BOOL_BOOL, + TO_BOOL_INT, + TO_BOOL_LIST, + TO_BOOL_NONE, + TO_BOOL_STR, + }; + + inst(TO_BOOL, (unused/1, unused/2, value -- res)) { + #if ENABLE_SPECIALIZATION + _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_ToBool(value, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(TO_BOOL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int err = PyObject_IsTrue(value); DECREF_INPUTS(); ERROR_IF(err < 0, error); - if (err == 0) { - res = Py_True; + res = err ? Py_True : Py_False; + } + + inst(TO_BOOL_BOOL, (unused/1, unused/2, value -- value)) { + DEOPT_IF(!PyBool_Check(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + } + + inst(TO_BOOL_INT, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (_PyLong_IsZero((PyLongObject *)value)) { + assert(_Py_IsImmortal(value)); + res = Py_False; } else { + DECREF_INPUTS(); + res = Py_True; + } + } + + inst(TO_BOOL_LIST, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_SIZE(value) ? Py_True : Py_False; + DECREF_INPUTS(); + } + + inst(TO_BOOL_NONE, (unused/1, unused/2, value -- res)) { + // This one is a bit weird, because we expect *some* failures: + DEOPT_IF(!Py_IsNone(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_False; + } + + inst(TO_BOOL_STR, (unused/1, unused/2, value -- res)) { + DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (value == &_Py_STR(empty)) { + assert(_Py_IsImmortal(value)); res = Py_False; } + else { + assert(Py_SIZE(value)); + DECREF_INPUTS(); + res = Py_True; + } + } + + inst(TO_BOOL_ALWAYS_TRUE, (unused/1, version/2, value -- res)) { + // This one is a bit weird, because we expect *some* failures: + assert(version); + DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); + STAT_INC(TO_BOOL, hit); + DECREF_INPUTS(); + res = Py_True; } inst(UNARY_INVERT, (value -- res)) { @@ -2024,10 +2099,16 @@ dummy_func( STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); + assert((oparg >> 5) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg >> 5); DECREF_INPUTS(); ERROR_IF(res == NULL, error); + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res); + Py_DECREF(res); + ERROR_IF(res_bool < 0, error); + res = res_bool ? Py_True : Py_False; + } } inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { @@ -2041,6 +2122,7 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } // Similar to COMPARE_OP_FLOAT @@ -2059,6 +2141,7 @@ dummy_func( _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } // Similar to COMPARE_OP_FLOAT, but for ==, != only @@ -2067,13 +2150,14 @@ dummy_func( DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + // It's always a bool, so we don't care about oparg & 16. } inst(IS_OP, (left, right -- b)) { @@ -2183,35 +2267,13 @@ dummy_func( } inst(POP_JUMP_IF_FALSE, (cond -- )) { - if (Py_IsFalse(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsTrue(cond)) { - int err = PyObject_IsTrue(cond); - DECREF_INPUTS(); - if (err == 0) { - JUMPBY(oparg); - } - else { - ERROR_IF(err < 0, error); - } - } + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsFalse(cond)); } inst(POP_JUMP_IF_TRUE, (cond -- )) { - if (Py_IsTrue(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsFalse(cond)) { - int err = PyObject_IsTrue(cond); - DECREF_INPUTS(); - if (err > 0) { - JUMPBY(oparg); - } - else { - ERROR_IF(err < 0, error); - } - } + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsTrue(cond)); } inst(POP_JUMP_IF_NOT_NONE, (value -- )) { @@ -3515,23 +3577,17 @@ dummy_func( inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) { PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = err*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) { PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = (1-err)*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } @@ -3558,7 +3614,7 @@ dummy_func( } else { Py_DECREF(value); - offset = oparg; + offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); } diff --git a/Python/compile.c b/Python/compile.c index 5936184d8b76b4..d83bf0855ec257 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2790,9 +2790,11 @@ static int compiler_addcompare(struct compiler *c, location loc, default: Py_UNREACHABLE(); } - /* cmp goes in top bits of the oparg, while the low bits are used by quickened - * versions of this opcode to store the comparison mask. */ - ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); + // cmp goes in top three bits of the oparg, while the low four bits are used + // by quickened versions of this opcode to store the comparison mask. The + // fifth-lowest bit indicates whether the result should be converted to bool + // and is set later): + ADDOP_I(c, loc, COMPARE_OP, (cmp << 5) | compare_masks[cmp]); return SUCCESS; } @@ -2858,10 +2860,12 @@ compiler_jump_if(struct compiler *c, location loc, ADDOP_I(c, LOC(e), SWAP, 2); ADDOP_I(c, LOC(e), COPY, 2); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, i)); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), POP_JUMP_IF_FALSE, cleanup); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, LOC(e), asdl_seq_GET(e->v.Compare.ops, n)); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); NEW_JUMP_TARGET_LABEL(c, end); ADDOP_JUMP(c, NO_LOCATION, JUMP, end); @@ -2885,6 +2889,7 @@ compiler_jump_if(struct compiler *c, location loc, /* general implementation */ VISIT(c, expr, e); + ADDOP(c, LOC(e), TO_BOOL); ADDOP_JUMP(c, LOC(e), cond ? POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE, next); return SUCCESS; } @@ -4016,8 +4021,6 @@ unaryop(unaryop_ty op) switch (op) { case Invert: return UNARY_INVERT; - case Not: - return UNARY_NOT; case USub: return UNARY_NEGATIVE; default: @@ -4247,6 +4250,7 @@ compiler_boolop(struct compiler *c, expr_ty e) for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); ADDOP_I(c, loc, COPY, 1); + ADDOP(c, loc, TO_BOOL); ADDOP_JUMP(c, loc, jumpi, end); ADDOP(c, loc, POP_TOP); } @@ -4554,6 +4558,7 @@ compiler_compare(struct compiler *c, expr_ty e) ADDOP_I(c, loc, COPY, 2); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_I(c, loc, COPY, 1); + ADDOP(c, loc, TO_BOOL); ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, cleanup); ADDOP(c, loc, POP_TOP); } @@ -5789,6 +5794,7 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k) static int compiler_with_except_finish(struct compiler *c, jump_target_label cleanup) { NEW_JUMP_TARGET_LABEL(c, suppress); + ADDOP(c, NO_LOCATION, TO_BOOL); ADDOP_JUMP(c, NO_LOCATION, POP_JUMP_IF_TRUE, suppress); ADDOP_I(c, NO_LOCATION, RERAISE, 2); @@ -6022,6 +6028,10 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) if (e->v.UnaryOp.op == UAdd) { ADDOP_I(c, loc, CALL_INTRINSIC_1, INTRINSIC_UNARY_POSITIVE); } + else if (e->v.UnaryOp.op == Not) { + ADDOP(c, loc, TO_BOOL); + ADDOP(c, loc, UNARY_NOT); + } else { ADDOP(c, loc, unaryop(e->v.UnaryOp.op)); } @@ -7197,6 +7207,7 @@ compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) } VISIT(c, expr, value); ADDOP_COMPARE(c, LOC(p), Eq); + ADDOP(c, LOC(p), TO_BOOL); RETURN_IF_ERROR(jump_to_fail_pop(c, LOC(p), pc, POP_JUMP_IF_FALSE)); return SUCCESS; } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index a64de0c958ce04..ea932232d7522a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -99,18 +99,105 @@ PyObject *value = stack_pointer[-1]; PyObject *res; #line 282 "Python/bytecodes.c" - int err = PyObject_IsTrue(value); - #line 104 "Python/executor_cases.c.h" - Py_DECREF(value); - #line 284 "Python/bytecodes.c" - if (err < 0) goto pop_1_error; - if (err == 0) { - res = Py_True; + assert(PyBool_Check(value)); + res = Py_IsFalse(value) ? Py_True : Py_False; + #line 105 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + + case TO_BOOL_BOOL: { + PyObject *value = stack_pointer[-1]; + #line 314 "Python/bytecodes.c" + DEOPT_IF(!PyBool_Check(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + #line 115 "Python/executor_cases.c.h" + break; + } + + case TO_BOOL_INT: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 319 "Python/bytecodes.c" + DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (_PyLong_IsZero((PyLongObject *)value)) { + assert(_Py_IsImmortal(value)); + res = Py_False; } else { + #line 130 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 327 "Python/bytecodes.c" + res = Py_True; + } + #line 135 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + + case TO_BOOL_LIST: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 332 "Python/bytecodes.c" + DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_SIZE(value) ? Py_True : Py_False; + #line 147 "Python/executor_cases.c.h" + Py_DECREF(value); + stack_pointer[-1] = res; + break; + } + + case TO_BOOL_NONE: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 339 "Python/bytecodes.c" + // This one is a bit weird, because we expect *some* failures: + DEOPT_IF(!Py_IsNone(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_False; + #line 161 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + + case TO_BOOL_STR: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 346 "Python/bytecodes.c" + DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (value == &_Py_STR(empty)) { + assert(_Py_IsImmortal(value)); res = Py_False; } - #line 114 "Python/executor_cases.c.h" + else { + assert(Py_SIZE(value)); + #line 178 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 355 "Python/bytecodes.c" + res = Py_True; + } + #line 183 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + + case TO_BOOL_ALWAYS_TRUE: { + PyObject *value = stack_pointer[-1]; + PyObject *res; + uint32_t version = operand; + #line 360 "Python/bytecodes.c" + // This one is a bit weird, because we expect *some* failures: + assert(version); + DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); + STAT_INC(TO_BOOL, hit); + #line 197 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 365 "Python/bytecodes.c" + res = Py_True; + #line 201 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -118,13 +205,13 @@ case UNARY_INVERT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 294 "Python/bytecodes.c" + #line 369 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 124 "Python/executor_cases.c.h" + #line 211 "Python/executor_cases.c.h" Py_DECREF(value); - #line 296 "Python/bytecodes.c" + #line 371 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 128 "Python/executor_cases.c.h" + #line 215 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -132,10 +219,10 @@ case _GUARD_BOTH_INT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 312 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 139 "Python/executor_cases.c.h" + #line 226 "Python/executor_cases.c.h" break; } @@ -143,13 +230,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 317 "Python/bytecodes.c" + #line 392 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 153 "Python/executor_cases.c.h" + #line 240 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -159,13 +246,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 325 "Python/bytecodes.c" + #line 400 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 169 "Python/executor_cases.c.h" + #line 256 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -175,13 +262,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 333 "Python/bytecodes.c" + #line 408 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 185 "Python/executor_cases.c.h" + #line 272 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -190,10 +277,10 @@ case _GUARD_BOTH_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 348 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 197 "Python/executor_cases.c.h" + #line 284 "Python/executor_cases.c.h" break; } @@ -201,13 +288,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 353 "Python/bytecodes.c" + #line 428 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 211 "Python/executor_cases.c.h" + #line 298 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -217,13 +304,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 361 "Python/bytecodes.c" + #line 436 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 227 "Python/executor_cases.c.h" + #line 314 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -233,13 +320,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 369 "Python/bytecodes.c" + #line 444 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 243 "Python/executor_cases.c.h" + #line 330 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -248,10 +335,10 @@ case _GUARD_BOTH_UNICODE: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 384 "Python/bytecodes.c" + #line 459 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 255 "Python/executor_cases.c.h" + #line 342 "Python/executor_cases.c.h" break; } @@ -259,13 +346,13 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 389 "Python/bytecodes.c" + #line 464 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 269 "Python/executor_cases.c.h" + #line 356 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -276,7 +363,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 459 "Python/bytecodes.c" + #line 534 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -289,7 +376,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 293 "Python/executor_cases.c.h" + #line 380 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -300,7 +387,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 474 "Python/bytecodes.c" + #line 549 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -313,7 +400,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 317 "Python/executor_cases.c.h" + #line 404 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -322,7 +409,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 489 "Python/bytecodes.c" + #line 564 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -336,7 +423,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 340 "Python/executor_cases.c.h" + #line 427 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -346,7 +433,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 505 "Python/bytecodes.c" + #line 580 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -360,7 +447,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 364 "Python/executor_cases.c.h" + #line 451 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -370,7 +457,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 521 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -378,14 +465,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 382 "Python/executor_cases.c.h" + #line 469 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 529 "Python/bytecodes.c" + #line 604 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 389 "Python/executor_cases.c.h" + #line 476 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -396,9 +483,9 @@ case LIST_APPEND: { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 561 "Python/bytecodes.c" + #line 636 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 402 "Python/executor_cases.c.h" + #line 489 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -406,13 +493,13 @@ case SET_ADD: { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 565 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 412 "Python/executor_cases.c.h" + #line 499 "Python/executor_cases.c.h" Py_DECREF(v); - #line 567 "Python/bytecodes.c" + #line 642 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 416 "Python/executor_cases.c.h" + #line 503 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -421,7 +508,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 596 "Python/bytecodes.c" + #line 671 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -438,7 +525,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 442 "Python/executor_cases.c.h" + #line 529 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -447,13 +534,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 615 "Python/bytecodes.c" + #line 690 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 457 "Python/executor_cases.c.h" + #line 544 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -461,15 +548,15 @@ case DELETE_SUBSCR: { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 623 "Python/bytecodes.c" + #line 698 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 468 "Python/executor_cases.c.h" + #line 555 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 626 "Python/bytecodes.c" + #line 701 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 473 "Python/executor_cases.c.h" + #line 560 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -477,14 +564,14 @@ case CALL_INTRINSIC_1: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 630 "Python/bytecodes.c" + #line 705 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 484 "Python/executor_cases.c.h" + #line 571 "Python/executor_cases.c.h" Py_DECREF(value); - #line 633 "Python/bytecodes.c" + #line 708 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 488 "Python/executor_cases.c.h" + #line 575 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -493,15 +580,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 637 "Python/bytecodes.c" + #line 712 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 500 "Python/executor_cases.c.h" + #line 587 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 640 "Python/bytecodes.c" + #line 715 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 505 "Python/executor_cases.c.h" + #line 592 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -510,7 +597,7 @@ case GET_AITER: { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 745 "Python/bytecodes.c" + #line 820 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -523,16 +610,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 527 "Python/executor_cases.c.h" + #line 614 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 758 "Python/bytecodes.c" + #line 833 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 534 "Python/executor_cases.c.h" + #line 621 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 763 "Python/bytecodes.c" + #line 838 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -545,7 +632,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 549 "Python/executor_cases.c.h" + #line 636 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -553,7 +640,7 @@ case GET_ANEXT: { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 778 "Python/bytecodes.c" + #line 853 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -596,7 +683,7 @@ Py_DECREF(next_iter); } } - #line 600 "Python/executor_cases.c.h" + #line 687 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -605,16 +692,16 @@ case GET_AWAITABLE: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 823 "Python/bytecodes.c" + #line 898 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 616 "Python/executor_cases.c.h" + #line 703 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 830 "Python/bytecodes.c" + #line 905 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -631,26 +718,26 @@ } if (iter == NULL) goto pop_1_error; - #line 635 "Python/executor_cases.c.h" + #line 722 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } case POP_EXCEPT: { PyObject *exc_value = stack_pointer[-1]; - #line 960 "Python/bytecodes.c" + #line 1035 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 645 "Python/executor_cases.c.h" + #line 732 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case LOAD_ASSERTION_ERROR: { PyObject *value; - #line 1011 "Python/bytecodes.c" + #line 1086 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 654 "Python/executor_cases.c.h" + #line 741 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -658,7 +745,7 @@ case LOAD_BUILD_CLASS: { PyObject *bc; - #line 1015 "Python/bytecodes.c" + #line 1090 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -680,7 +767,7 @@ if (true) goto error; } } - #line 684 "Python/executor_cases.c.h" + #line 771 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -688,33 +775,33 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; - #line 1040 "Python/bytecodes.c" + #line 1115 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 699 "Python/executor_cases.c.h" + #line 786 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1047 "Python/bytecodes.c" + #line 1122 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 708 "Python/executor_cases.c.h" + #line 795 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1054 "Python/bytecodes.c" + #line 1129 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 712 "Python/executor_cases.c.h" + #line 799 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_NAME: { - #line 1058 "Python/bytecodes.c" + #line 1133 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -731,21 +818,21 @@ name); goto error; } - #line 735 "Python/executor_cases.c.h" + #line 822 "Python/executor_cases.c.h" break; } case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1101 "Python/bytecodes.c" + #line 1176 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 749 "Python/executor_cases.c.h" + #line 836 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -755,7 +842,7 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1111 "Python/bytecodes.c" + #line 1186 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -763,7 +850,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 767 "Python/executor_cases.c.h" + #line 854 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -773,7 +860,7 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1122 "Python/bytecodes.c" + #line 1197 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -781,7 +868,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 785 "Python/executor_cases.c.h" + #line 872 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -790,49 +877,49 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; - #line 1133 "Python/bytecodes.c" + #line 1208 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 798 "Python/executor_cases.c.h" + #line 885 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1137 "Python/bytecodes.c" + #line 1212 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 802 "Python/executor_cases.c.h" + #line 889 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; - #line 1168 "Python/bytecodes.c" + #line 1243 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 812 "Python/executor_cases.c.h" + #line 899 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1171 "Python/bytecodes.c" + #line 1246 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 816 "Python/executor_cases.c.h" + #line 903 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; - #line 1175 "Python/bytecodes.c" + #line 1250 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 826 "Python/executor_cases.c.h" + #line 913 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1178 "Python/bytecodes.c" + #line 1253 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 830 "Python/executor_cases.c.h" + #line 917 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_GLOBAL: { - #line 1182 "Python/bytecodes.c" + #line 1257 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -844,13 +931,13 @@ } goto error; } - #line 848 "Python/executor_cases.c.h" + #line 935 "Python/executor_cases.c.h" break; } case _LOAD_LOCALS: { PyObject *locals; - #line 1196 "Python/bytecodes.c" + #line 1271 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -858,7 +945,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 862 "Python/executor_cases.c.h" + #line 949 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -867,7 +954,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; - #line 1208 "Python/bytecodes.c" + #line 1283 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -924,13 +1011,13 @@ } } } - #line 928 "Python/executor_cases.c.h" + #line 1015 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } case DELETE_DEREF: { - #line 1378 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -941,14 +1028,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 945 "Python/executor_cases.c.h" + #line 1032 "Python/executor_cases.c.h" break; } case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1391 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -983,14 +1070,14 @@ } Py_INCREF(value); } - #line 987 "Python/executor_cases.c.h" + #line 1074 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } case LOAD_DEREF: { PyObject *value; - #line 1428 "Python/bytecodes.c" + #line 1503 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -998,7 +1085,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1002 "Python/executor_cases.c.h" + #line 1089 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1006,18 +1093,18 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1438 "Python/bytecodes.c" + #line 1513 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1015 "Python/executor_cases.c.h" + #line 1102 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case COPY_FREE_VARS: { - #line 1445 "Python/bytecodes.c" + #line 1520 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1028,22 +1115,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1032 "Python/executor_cases.c.h" + #line 1119 "Python/executor_cases.c.h" break; } case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1458 "Python/bytecodes.c" + #line 1533 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1041 "Python/executor_cases.c.h" + #line 1128 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1460 "Python/bytecodes.c" + #line 1535 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1047 "Python/executor_cases.c.h" + #line 1134 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1053,10 +1140,10 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1464 "Python/bytecodes.c" + #line 1539 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1060 "Python/executor_cases.c.h" + #line 1147 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1066,10 +1153,10 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1469 "Python/bytecodes.c" + #line 1544 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1073 "Python/executor_cases.c.h" + #line 1160 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1079,7 +1166,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1474 "Python/bytecodes.c" + #line 1549 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1090,13 +1177,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1094 "Python/executor_cases.c.h" + #line 1181 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1485 "Python/bytecodes.c" + #line 1560 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1100 "Python/executor_cases.c.h" + #line 1187 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1105,13 +1192,13 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1492 "Python/bytecodes.c" + #line 1567 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1111 "Python/executor_cases.c.h" + #line 1198 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1494 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1115 "Python/executor_cases.c.h" + #line 1202 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1119,7 +1206,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1498 "Python/bytecodes.c" + #line 1573 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1134,7 +1221,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1138 "Python/executor_cases.c.h" + #line 1225 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1144,7 +1231,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1515 "Python/bytecodes.c" + #line 1590 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1152,13 +1239,13 @@ if (map == NULL) goto error; - #line 1156 "Python/executor_cases.c.h" + #line 1243 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1523 "Python/bytecodes.c" + #line 1598 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1162 "Python/executor_cases.c.h" + #line 1249 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1166,7 +1253,7 @@ } case SETUP_ANNOTATIONS: { - #line 1527 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1206,7 +1293,7 @@ Py_DECREF(ann_dict); } } - #line 1210 "Python/executor_cases.c.h" + #line 1297 "Python/executor_cases.c.h" break; } @@ -1214,7 +1301,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1569 "Python/bytecodes.c" + #line 1644 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1224,14 +1311,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1228 "Python/executor_cases.c.h" + #line 1315 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1579 "Python/bytecodes.c" + #line 1654 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1235 "Python/executor_cases.c.h" + #line 1322 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1239,7 +1326,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1583 "Python/bytecodes.c" + #line 1658 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1247,12 +1334,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1251 "Python/executor_cases.c.h" + #line 1338 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1591 "Python/bytecodes.c" + #line 1666 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1256 "Python/executor_cases.c.h" + #line 1343 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1260,17 +1347,17 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1597 "Python/bytecodes.c" + #line 1672 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1269 "Python/executor_cases.c.h" + #line 1356 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1602 "Python/bytecodes.c" + #line 1677 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1274 "Python/executor_cases.c.h" + #line 1361 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1279,13 +1366,13 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1608 "Python/bytecodes.c" + #line 1683 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1289 "Python/executor_cases.c.h" + #line 1376 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1296,20 +1383,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1691 "Python/bytecodes.c" + #line 1766 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1307 "Python/executor_cases.c.h" + #line 1394 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1698 "Python/bytecodes.c" + #line 1773 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1313 "Python/executor_cases.c.h" + #line 1400 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1323,7 +1410,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1702 "Python/bytecodes.c" + #line 1777 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1346,7 +1433,7 @@ res = res2; res2 = NULL; } - #line 1350 "Python/executor_cases.c.h" + #line 1437 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1357,7 +1444,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2034 "Python/bytecodes.c" + #line 2115 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1368,7 +1455,8 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 1372 "Python/executor_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 1460 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1378,7 +1466,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2048 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1393,7 +1481,8 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 1397 "Python/executor_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 1486 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1403,19 +1492,20 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2066 "Python/bytecodes.c" + #line 2149 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 1419 "Python/executor_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 1509 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1425,14 +1515,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2080 "Python/bytecodes.c" + #line 2164 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1431 "Python/executor_cases.c.h" + #line 1521 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2082 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1436 "Python/executor_cases.c.h" + #line 1526 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1442,15 +1532,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2086 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1448 "Python/executor_cases.c.h" + #line 1538 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2088 "Python/bytecodes.c" + #line 2172 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1454 "Python/executor_cases.c.h" + #line 1544 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1461,12 +1551,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2093 "Python/bytecodes.c" + #line 2177 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1467 "Python/executor_cases.c.h" + #line 1557 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2095 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1474,10 +1564,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1478 "Python/executor_cases.c.h" + #line 1568 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2103 "Python/bytecodes.c" + #line 2187 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1486,7 +1576,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1490 "Python/executor_cases.c.h" + #line 1580 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1496,21 +1586,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2114 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1503 "Python/executor_cases.c.h" + #line 1593 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2117 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1510 "Python/executor_cases.c.h" + #line 1600 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2122 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1514 "Python/executor_cases.c.h" + #line 1604 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1518,13 +1608,13 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2243 "Python/bytecodes.c" + #line 2305 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1528 "Python/executor_cases.c.h" + #line 1618 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1535,16 +1625,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2251 "Python/bytecodes.c" + #line 2313 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1544 "Python/executor_cases.c.h" + #line 1634 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2256 "Python/bytecodes.c" + #line 2318 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1552,7 +1642,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1556 "Python/executor_cases.c.h" + #line 1646 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1561,10 +1651,10 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2266 "Python/bytecodes.c" + #line 2328 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1568 "Python/executor_cases.c.h" + #line 1658 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1573,10 +1663,10 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2271 "Python/bytecodes.c" + #line 2333 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1580 "Python/executor_cases.c.h" + #line 1670 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1586,11 +1676,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2276 "Python/bytecodes.c" + #line 2338 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1594 "Python/executor_cases.c.h" + #line 1684 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1599,14 +1689,14 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2282 "Python/bytecodes.c" + #line 2344 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1606 "Python/executor_cases.c.h" + #line 1696 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2285 "Python/bytecodes.c" + #line 2347 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1610 "Python/executor_cases.c.h" + #line 1700 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1614,7 +1704,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2289 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1637,11 +1727,11 @@ if (iter == NULL) { goto error; } - #line 1641 "Python/executor_cases.c.h" + #line 1731 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2312 "Python/bytecodes.c" + #line 2374 "Python/bytecodes.c" } - #line 1645 "Python/executor_cases.c.h" + #line 1735 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1651,7 +1741,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2544 "Python/bytecodes.c" + #line 2606 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -1672,7 +1762,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 1676 "Python/executor_cases.c.h" + #line 1766 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1681,7 +1771,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2583 "Python/bytecodes.c" + #line 2645 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -1691,7 +1781,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 1695 "Python/executor_cases.c.h" + #line 1785 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -1700,7 +1790,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 2952 "Python/bytecodes.c" + #line 3014 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1708,7 +1798,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 1712 "Python/executor_cases.c.h" + #line 1802 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1716,7 +1806,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3366 "Python/bytecodes.c" + #line 3428 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1728,7 +1818,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 1732 "Python/executor_cases.c.h" + #line 1822 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -1736,7 +1826,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3380 "Python/bytecodes.c" + #line 3442 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1761,7 +1851,7 @@ default: Py_UNREACHABLE(); } - #line 1765 "Python/executor_cases.c.h" + #line 1855 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -1772,15 +1862,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3430 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 1778 "Python/executor_cases.c.h" + #line 1868 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3432 "Python/bytecodes.c" + #line 3494 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 1784 "Python/executor_cases.c.h" + #line 1874 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -1790,14 +1880,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3436 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 1801 "Python/executor_cases.c.h" + #line 1891 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -1805,7 +1895,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3445 "Python/bytecodes.c" + #line 3507 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1816,7 +1906,7 @@ else { res = value; } - #line 1820 "Python/executor_cases.c.h" + #line 1910 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -1825,12 +1915,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3458 "Python/bytecodes.c" + #line 3520 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 1834 "Python/executor_cases.c.h" + #line 1924 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1839,10 +1929,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3465 "Python/bytecodes.c" + #line 3527 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 1846 "Python/executor_cases.c.h" + #line 1936 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -1851,9 +1941,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3490 "Python/bytecodes.c" + #line 3552 "Python/bytecodes.c" assert(oparg >= 2); - #line 1857 "Python/executor_cases.c.h" + #line 1947 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index d78fb92e0d67dd..429109b74beab8 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1044,6 +1044,36 @@ get_const_value(int opcode, int oparg, PyObject *co_consts) return Py_NewRef(constant); } +// Steals a reference to newconst. +static int +add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache) +{ + if (_PyCompile_ConstCacheMergeOne(const_cache, &newconst) < 0) { + Py_DECREF(newconst); + return -1; + } + + Py_ssize_t index; + for (index = 0; index < PyList_GET_SIZE(consts); index++) { + if (PyList_GET_ITEM(consts, index) == newconst) { + break; + } + } + if (index == PyList_GET_SIZE(consts)) { + if ((size_t)index >= (size_t)INT_MAX - 1) { + PyErr_SetString(PyExc_OverflowError, "too many constants"); + Py_DECREF(newconst); + return -1; + } + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return -1; + } + } + Py_DECREF(newconst); + return (int)index; +} + /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n with LOAD_CONST (c1, c2, ... cn). The consts table must still be in list form so that the @@ -1081,33 +1111,14 @@ fold_tuple_on_constants(PyObject *const_cache, } PyTuple_SET_ITEM(newconst, i, constant); } - if (_PyCompile_ConstCacheMergeOne(const_cache, &newconst) < 0) { - Py_DECREF(newconst); + int index = add_const(newconst, consts, const_cache); + if (index < 0) { return ERROR; } - - Py_ssize_t index; - for (index = 0; index < PyList_GET_SIZE(consts); index++) { - if (PyList_GET_ITEM(consts, index) == newconst) { - break; - } - } - if (index == PyList_GET_SIZE(consts)) { - if ((size_t)index >= (size_t)INT_MAX - 1) { - Py_DECREF(newconst); - PyErr_SetString(PyExc_OverflowError, "too many constants"); - return ERROR; - } - if (PyList_Append(consts, newconst)) { - Py_DECREF(newconst); - return ERROR; - } - } - Py_DECREF(newconst); 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, index); return SUCCESS; } @@ -1361,24 +1372,71 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) } break; case IS_OP: + // Fold to POP_JUMP_IF_NONE: + // - LOAD_CONST(None) IS_OP(0) POP_JUMP_IF_TRUE + // - LOAD_CONST(None) IS_OP(1) POP_JUMP_IF_FALSE + // - LOAD_CONST(None) IS_OP(0) TO_BOOL POP_JUMP_IF_TRUE + // - LOAD_CONST(None) IS_OP(1) TO_BOOL POP_JUMP_IF_FALSE + // Fold to POP_JUMP_IF_NOT_NONE: + // - LOAD_CONST(None) IS_OP(0) POP_JUMP_IF_FALSE + // - LOAD_CONST(None) IS_OP(1) POP_JUMP_IF_TRUE + // - LOAD_CONST(None) IS_OP(0) TO_BOOL POP_JUMP_IF_FALSE + // - LOAD_CONST(None) IS_OP(1) TO_BOOL POP_JUMP_IF_TRUE cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } - int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0; - if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) { - unsigned char nextarg = bb->b_instr[i+1].i_oparg; - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ? - POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE; + if (!Py_IsNone(cnt)) { + break; } Py_DECREF(cnt); + if (bb->b_iused <= i + 2) { + break; + } + cfg_instr *is_instr = &bb->b_instr[i + 1]; + cfg_instr *jump_instr = &bb->b_instr[i + 2]; + // Get rid of TO_BOOL regardless: + if (jump_instr->i_opcode == TO_BOOL) { + INSTR_SET_OP0(jump_instr, NOP); + if (bb->b_iused <= i + 3) { + break; + } + jump_instr = &bb->b_instr[i + 3]; + } + bool invert = is_instr->i_oparg; + if (jump_instr->i_opcode == POP_JUMP_IF_FALSE) { + invert = !invert; + } + else if (jump_instr->i_opcode != POP_JUMP_IF_TRUE) { + break; + } + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP0(is_instr, NOP); + jump_instr->i_opcode = invert ? POP_JUMP_IF_NOT_NONE + : POP_JUMP_IF_NONE; break; case RETURN_VALUE: INSTR_SET_OP0(inst, NOP); INSTR_SET_OP1(&bb->b_instr[++i], RETURN_CONST, oparg); break; + case TO_BOOL: + cnt = get_const_value(opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } + is_true = PyObject_IsTrue(cnt); + Py_DECREF(cnt); + if (is_true == -1) { + goto error; + } + cnt = PyBool_FromLong(is_true); + int index = add_const(cnt, consts, const_cache); + if (index < 0) { + return ERROR; + } + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP1(&bb->b_instr[i + 1], LOAD_CONST, index); + break; } break; } @@ -1464,6 +1522,39 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) inst[1].i_oparg |= 1; } break; + case COMPARE_OP: + if (nextop == TO_BOOL) { + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP1(&bb->b_instr[i + 1], COMPARE_OP, oparg | 16); + continue; + } + break; + case CONTAINS_OP: + case IS_OP: + if (nextop == TO_BOOL) { + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP1(&bb->b_instr[i + 1], opcode, oparg); + continue; + } + break; + case TO_BOOL: + if (nextop == TO_BOOL) { + INSTR_SET_OP0(inst, NOP); + continue; + } + break; + case UNARY_NOT: + if (nextop == TO_BOOL) { + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP0(&bb->b_instr[i + 1], UNARY_NOT); + continue; + } + if (nextop == UNARY_NOT) { + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); + continue; + } + break; default: /* All OPCODE_HAS_CONST opcodes should be handled with LOAD_CONST */ assert (!OPCODE_HAS_CONST(inst->i_opcode)); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 44b4522c9a5f1e..568d15ee7edf23 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -260,32 +260,153 @@ PyObject *value = stack_pointer[-1]; PyObject *res; #line 282 "Python/bytecodes.c" + assert(PyBool_Check(value)); + res = Py_IsFalse(value) ? Py_True : Py_False; + #line 266 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + DISPATCH(); + } + + TARGET(TO_BOOL) { + PREDICTED(TO_BOOL); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 297 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_ToBool(value, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(TO_BOOL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ int err = PyObject_IsTrue(value); - #line 265 "Python/generated_cases.c.h" + #line 288 "Python/generated_cases.c.h" Py_DECREF(value); - #line 284 "Python/bytecodes.c" + #line 309 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - if (err == 0) { - res = Py_True; + res = err ? Py_True : Py_False; + #line 293 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_BOOL) { + PyObject *value = stack_pointer[-1]; + #line 314 "Python/bytecodes.c" + DEOPT_IF(!PyBool_Check(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + #line 304 "Python/generated_cases.c.h" + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_INT) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 319 "Python/bytecodes.c" + DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (_PyLong_IsZero((PyLongObject *)value)) { + assert(_Py_IsImmortal(value)); + res = Py_False; } else { + #line 320 "Python/generated_cases.c.h" + Py_DECREF(value); + #line 327 "Python/bytecodes.c" + res = Py_True; + } + #line 325 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_LIST) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 332 "Python/bytecodes.c" + DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_SIZE(value) ? Py_True : Py_False; + #line 338 "Python/generated_cases.c.h" + Py_DECREF(value); + stack_pointer[-1] = res; + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_NONE) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 339 "Python/bytecodes.c" + // This one is a bit weird, because we expect *some* failures: + DEOPT_IF(!Py_IsNone(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + res = Py_False; + #line 353 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_STR) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 346 "Python/bytecodes.c" + DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); + STAT_INC(TO_BOOL, hit); + if (value == &_Py_STR(empty)) { + assert(_Py_IsImmortal(value)); res = Py_False; } - #line 275 "Python/generated_cases.c.h" + else { + assert(Py_SIZE(value)); + #line 371 "Python/generated_cases.c.h" + Py_DECREF(value); + #line 355 "Python/bytecodes.c" + res = Py_True; + } + #line 376 "Python/generated_cases.c.h" stack_pointer[-1] = res; + next_instr += 3; + DISPATCH(); + } + + TARGET(TO_BOOL_ALWAYS_TRUE) { + PyObject *value = stack_pointer[-1]; + PyObject *res; + uint32_t version = read_u32(&next_instr[1].cache); + #line 360 "Python/bytecodes.c" + // This one is a bit weird, because we expect *some* failures: + assert(version); + DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); + STAT_INC(TO_BOOL, hit); + #line 391 "Python/generated_cases.c.h" + Py_DECREF(value); + #line 365 "Python/bytecodes.c" + res = Py_True; + #line 395 "Python/generated_cases.c.h" + stack_pointer[-1] = res; + next_instr += 3; DISPATCH(); } TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 294 "Python/bytecodes.c" + #line 369 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 285 "Python/generated_cases.c.h" + #line 406 "Python/generated_cases.c.h" Py_DECREF(value); - #line 296 "Python/bytecodes.c" + #line 371 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 289 "Python/generated_cases.c.h" + #line 410 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -296,10 +417,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 312 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 303 "Python/generated_cases.c.h" + #line 424 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -307,13 +428,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 317 "Python/bytecodes.c" + #line 392 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 317 "Python/generated_cases.c.h" + #line 438 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -328,10 +449,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 312 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 335 "Python/generated_cases.c.h" + #line 456 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -339,13 +460,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 325 "Python/bytecodes.c" + #line 400 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 349 "Python/generated_cases.c.h" + #line 470 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -360,10 +481,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 312 "Python/bytecodes.c" + #line 387 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 367 "Python/generated_cases.c.h" + #line 488 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -371,13 +492,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 333 "Python/bytecodes.c" + #line 408 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 381 "Python/generated_cases.c.h" + #line 502 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -392,10 +513,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 348 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 399 "Python/generated_cases.c.h" + #line 520 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -403,13 +524,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 353 "Python/bytecodes.c" + #line 428 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 413 "Python/generated_cases.c.h" + #line 534 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -424,10 +545,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 348 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 431 "Python/generated_cases.c.h" + #line 552 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -435,13 +556,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 361 "Python/bytecodes.c" + #line 436 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 445 "Python/generated_cases.c.h" + #line 566 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -456,10 +577,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 348 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 463 "Python/generated_cases.c.h" + #line 584 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -467,13 +588,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 369 "Python/bytecodes.c" + #line 444 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 477 "Python/generated_cases.c.h" + #line 598 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -488,10 +609,10 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 384 "Python/bytecodes.c" + #line 459 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 495 "Python/generated_cases.c.h" + #line 616 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -499,13 +620,13 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 389 "Python/bytecodes.c" + #line 464 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 509 "Python/generated_cases.c.h" + #line 630 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -520,17 +641,17 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 384 "Python/bytecodes.c" + #line 459 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 527 "Python/generated_cases.c.h" + #line 648 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 406 "Python/bytecodes.c" + #line 481 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -554,7 +675,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 558 "Python/generated_cases.c.h" + #line 679 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -566,7 +687,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 443 "Python/bytecodes.c" + #line 518 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -578,12 +699,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 582 "Python/generated_cases.c.h" + #line 703 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 455 "Python/bytecodes.c" + #line 530 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 587 "Python/generated_cases.c.h" + #line 708 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -595,7 +716,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 459 "Python/bytecodes.c" + #line 534 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -608,7 +729,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 612 "Python/generated_cases.c.h" + #line 733 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -619,7 +740,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 474 "Python/bytecodes.c" + #line 549 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -632,7 +753,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 636 "Python/generated_cases.c.h" + #line 757 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -641,7 +762,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 489 "Python/bytecodes.c" + #line 564 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -655,7 +776,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 659 "Python/generated_cases.c.h" + #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -666,7 +787,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 505 "Python/bytecodes.c" + #line 580 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -680,7 +801,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 684 "Python/generated_cases.c.h" + #line 805 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -691,7 +812,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 521 "Python/bytecodes.c" + #line 596 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -699,14 +820,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 703 "Python/generated_cases.c.h" + #line 824 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 529 "Python/bytecodes.c" + #line 604 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 710 "Python/generated_cases.c.h" + #line 831 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -718,7 +839,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 536 "Python/bytecodes.c" + #line 611 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -741,15 +862,15 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 745 "Python/generated_cases.c.h" + #line 866 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 561 "Python/bytecodes.c" + #line 636 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 753 "Python/generated_cases.c.h" + #line 874 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -757,13 +878,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 565 "Python/bytecodes.c" + #line 640 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 763 "Python/generated_cases.c.h" + #line 884 "Python/generated_cases.c.h" Py_DECREF(v); - #line 567 "Python/bytecodes.c" + #line 642 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 767 "Python/generated_cases.c.h" + #line 888 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -775,7 +896,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 577 "Python/bytecodes.c" + #line 652 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -790,13 +911,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 794 "Python/generated_cases.c.h" + #line 915 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 592 "Python/bytecodes.c" + #line 667 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 800 "Python/generated_cases.c.h" + #line 921 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -806,7 +927,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 596 "Python/bytecodes.c" + #line 671 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -823,7 +944,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 827 "Python/generated_cases.c.h" + #line 948 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -833,13 +954,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 615 "Python/bytecodes.c" + #line 690 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 843 "Python/generated_cases.c.h" + #line 964 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -848,15 +969,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 623 "Python/bytecodes.c" + #line 698 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 855 "Python/generated_cases.c.h" + #line 976 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 626 "Python/bytecodes.c" + #line 701 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 860 "Python/generated_cases.c.h" + #line 981 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -864,14 +985,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 630 "Python/bytecodes.c" + #line 705 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 871 "Python/generated_cases.c.h" + #line 992 "Python/generated_cases.c.h" Py_DECREF(value); - #line 633 "Python/bytecodes.c" + #line 708 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 875 "Python/generated_cases.c.h" + #line 996 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -880,15 +1001,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 637 "Python/bytecodes.c" + #line 712 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 887 "Python/generated_cases.c.h" + #line 1008 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 640 "Python/bytecodes.c" + #line 715 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 892 "Python/generated_cases.c.h" + #line 1013 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -896,7 +1017,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 644 "Python/bytecodes.c" + #line 719 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -914,12 +1035,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 918 "Python/generated_cases.c.h" + #line 1039 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 664 "Python/bytecodes.c" + #line 739 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -928,12 +1049,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 932 "Python/generated_cases.c.h" + #line 1053 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 675 "Python/bytecodes.c" + #line 750 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -946,12 +1067,12 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 950 "Python/generated_cases.c.h" + #line 1071 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 690 "Python/bytecodes.c" + #line 765 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -968,11 +1089,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 972 "Python/generated_cases.c.h" + #line 1093 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 709 "Python/bytecodes.c" + #line 784 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -986,11 +1107,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 990 "Python/generated_cases.c.h" + #line 1111 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 725 "Python/bytecodes.c" + #line 800 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1008,13 +1129,13 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1012 "Python/generated_cases.c.h" + #line 1133 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 745 "Python/bytecodes.c" + #line 820 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1027,16 +1148,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1031 "Python/generated_cases.c.h" + #line 1152 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 758 "Python/bytecodes.c" + #line 833 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1038 "Python/generated_cases.c.h" + #line 1159 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 763 "Python/bytecodes.c" + #line 838 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1049,7 +1170,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1053 "Python/generated_cases.c.h" + #line 1174 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1057,7 +1178,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 778 "Python/bytecodes.c" + #line 853 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1100,7 +1221,7 @@ Py_DECREF(next_iter); } } - #line 1104 "Python/generated_cases.c.h" + #line 1225 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; DISPATCH(); @@ -1109,16 +1230,16 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 823 "Python/bytecodes.c" + #line 898 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1120 "Python/generated_cases.c.h" + #line 1241 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 830 "Python/bytecodes.c" + #line 905 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1135,7 +1256,7 @@ } if (iter == NULL) goto pop_1_error; - #line 1139 "Python/generated_cases.c.h" + #line 1260 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1146,7 +1267,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 854 "Python/bytecodes.c" + #line 929 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1193,7 +1314,7 @@ } } Py_DECREF(v); - #line 1197 "Python/generated_cases.c.h" + #line 1318 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1202,7 +1323,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 903 "Python/bytecodes.c" + #line 978 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1218,12 +1339,12 @@ tstate->exc_info = &gen->gi_exc_state; SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1222 "Python/generated_cases.c.h" + #line 1343 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 921 "Python/bytecodes.c" + #line 996 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1241,12 +1362,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1245 "Python/generated_cases.c.h" + #line 1366 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 941 "Python/bytecodes.c" + #line 1016 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1263,15 +1384,15 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1267 "Python/generated_cases.c.h" + #line 1388 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 960 "Python/bytecodes.c" + #line 1035 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1275 "Python/generated_cases.c.h" + #line 1396 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1279,7 +1400,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 965 "Python/bytecodes.c" + #line 1040 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1297,26 +1418,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1301 "Python/generated_cases.c.h" + #line 1422 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 985 "Python/bytecodes.c" + #line 1060 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1310 "Python/generated_cases.c.h" + #line 1431 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 988 "Python/bytecodes.c" + #line 1063 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1320 "Python/generated_cases.c.h" + #line 1441 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1327,23 +1448,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 997 "Python/bytecodes.c" + #line 1072 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1336 "Python/generated_cases.c.h" + #line 1457 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1002 "Python/bytecodes.c" + #line 1077 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1347 "Python/generated_cases.c.h" + #line 1468 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1352,9 +1473,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1011 "Python/bytecodes.c" + #line 1086 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1358 "Python/generated_cases.c.h" + #line 1479 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1362,7 +1483,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1015 "Python/bytecodes.c" + #line 1090 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1384,7 +1505,7 @@ if (true) goto error; } } - #line 1388 "Python/generated_cases.c.h" + #line 1509 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1392,33 +1513,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1040 "Python/bytecodes.c" + #line 1115 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1403 "Python/generated_cases.c.h" + #line 1524 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1047 "Python/bytecodes.c" + #line 1122 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1412 "Python/generated_cases.c.h" + #line 1533 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1054 "Python/bytecodes.c" + #line 1129 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1416 "Python/generated_cases.c.h" + #line 1537 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1058 "Python/bytecodes.c" + #line 1133 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1435,7 +1556,7 @@ name); goto error; } - #line 1439 "Python/generated_cases.c.h" + #line 1560 "Python/generated_cases.c.h" DISPATCH(); } @@ -1443,7 +1564,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1084 "Python/bytecodes.c" + #line 1159 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1456,11 +1577,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1460 "Python/generated_cases.c.h" + #line 1581 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1097 "Python/bytecodes.c" + #line 1172 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1464 "Python/generated_cases.c.h" + #line 1585 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1470,14 +1591,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1101 "Python/bytecodes.c" + #line 1176 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1481 "Python/generated_cases.c.h" + #line 1602 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1488,7 +1609,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1111 "Python/bytecodes.c" + #line 1186 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1496,7 +1617,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1500 "Python/generated_cases.c.h" + #line 1621 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1507,7 +1628,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1122 "Python/bytecodes.c" + #line 1197 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1515,7 +1636,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1519 "Python/generated_cases.c.h" + #line 1640 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1525,15 +1646,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1133 "Python/bytecodes.c" + #line 1208 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1533 "Python/generated_cases.c.h" + #line 1654 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1137 "Python/bytecodes.c" + #line 1212 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1537 "Python/generated_cases.c.h" + #line 1658 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1544,7 +1665,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1148 "Python/bytecodes.c" + #line 1223 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1560,12 +1681,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1564 "Python/generated_cases.c.h" + #line 1685 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1164 "Python/bytecodes.c" + #line 1239 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1569 "Python/generated_cases.c.h" + #line 1690 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1573,34 +1694,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1168 "Python/bytecodes.c" + #line 1243 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1580 "Python/generated_cases.c.h" + #line 1701 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1171 "Python/bytecodes.c" + #line 1246 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1584 "Python/generated_cases.c.h" + #line 1705 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1175 "Python/bytecodes.c" + #line 1250 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1594 "Python/generated_cases.c.h" + #line 1715 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1178 "Python/bytecodes.c" + #line 1253 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1598 "Python/generated_cases.c.h" + #line 1719 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1182 "Python/bytecodes.c" + #line 1257 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1612,7 +1733,7 @@ } goto error; } - #line 1616 "Python/generated_cases.c.h" + #line 1737 "Python/generated_cases.c.h" DISPATCH(); } @@ -1620,7 +1741,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1196 "Python/bytecodes.c" + #line 1271 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1628,7 +1749,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1632 "Python/generated_cases.c.h" + #line 1753 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1640,7 +1761,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1196 "Python/bytecodes.c" + #line 1271 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1648,13 +1769,13 @@ if (true) goto error; } Py_INCREF(locals); - #line 1652 "Python/generated_cases.c.h" + #line 1773 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1208 "Python/bytecodes.c" + #line 1283 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1711,7 +1832,7 @@ } } } - #line 1715 "Python/generated_cases.c.h" + #line 1836 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1724,7 +1845,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1208 "Python/bytecodes.c" + #line 1283 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1781,7 +1902,7 @@ } } } - #line 1785 "Python/generated_cases.c.h" + #line 1906 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1793,7 +1914,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1277 "Python/bytecodes.c" + #line 1352 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1845,7 +1966,7 @@ } } null = NULL; - #line 1849 "Python/generated_cases.c.h" + #line 1970 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1859,7 +1980,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1331 "Python/bytecodes.c" + #line 1406 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1870,7 +1991,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1874 "Python/generated_cases.c.h" + #line 1995 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1885,7 +2006,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1344 "Python/bytecodes.c" + #line 1419 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -1900,7 +2021,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1904 "Python/generated_cases.c.h" + #line 2025 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1910,16 +2031,16 @@ } TARGET(DELETE_FAST) { - #line 1361 "Python/bytecodes.c" + #line 1436 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1918 "Python/generated_cases.c.h" + #line 2039 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1367 "Python/bytecodes.c" + #line 1442 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1928,12 +2049,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1932 "Python/generated_cases.c.h" + #line 2053 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1378 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1944,14 +2065,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1948 "Python/generated_cases.c.h" + #line 2069 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1391 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -1986,14 +2107,14 @@ } Py_INCREF(value); } - #line 1990 "Python/generated_cases.c.h" + #line 2111 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1428 "Python/bytecodes.c" + #line 1503 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2001,7 +2122,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2005 "Python/generated_cases.c.h" + #line 2126 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2009,18 +2130,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1438 "Python/bytecodes.c" + #line 1513 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2018 "Python/generated_cases.c.h" + #line 2139 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1445 "Python/bytecodes.c" + #line 1520 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2031,22 +2152,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2035 "Python/generated_cases.c.h" + #line 2156 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1458 "Python/bytecodes.c" + #line 1533 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2044 "Python/generated_cases.c.h" + #line 2165 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1460 "Python/bytecodes.c" + #line 1535 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2050 "Python/generated_cases.c.h" + #line 2171 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2056,10 +2177,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1464 "Python/bytecodes.c" + #line 1539 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2063 "Python/generated_cases.c.h" + #line 2184 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2069,10 +2190,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1469 "Python/bytecodes.c" + #line 1544 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2076 "Python/generated_cases.c.h" + #line 2197 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2082,7 +2203,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1474 "Python/bytecodes.c" + #line 1549 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2093,13 +2214,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2097 "Python/generated_cases.c.h" + #line 2218 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1485 "Python/bytecodes.c" + #line 1560 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2103 "Python/generated_cases.c.h" + #line 2224 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2108,13 +2229,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1492 "Python/bytecodes.c" + #line 1567 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2114 "Python/generated_cases.c.h" + #line 2235 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1494 "Python/bytecodes.c" + #line 1569 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2118 "Python/generated_cases.c.h" + #line 2239 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2122,7 +2243,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1498 "Python/bytecodes.c" + #line 1573 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2137,7 +2258,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2141 "Python/generated_cases.c.h" + #line 2262 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2147,7 +2268,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1515 "Python/bytecodes.c" + #line 1590 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2155,13 +2276,13 @@ if (map == NULL) goto error; - #line 2159 "Python/generated_cases.c.h" + #line 2280 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1523 "Python/bytecodes.c" + #line 1598 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2165 "Python/generated_cases.c.h" + #line 2286 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2169,7 +2290,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1527 "Python/bytecodes.c" + #line 1602 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2209,7 +2330,7 @@ Py_DECREF(ann_dict); } } - #line 2213 "Python/generated_cases.c.h" + #line 2334 "Python/generated_cases.c.h" DISPATCH(); } @@ -2217,7 +2338,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1569 "Python/bytecodes.c" + #line 1644 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2227,14 +2348,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2231 "Python/generated_cases.c.h" + #line 2352 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1579 "Python/bytecodes.c" + #line 1654 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2238 "Python/generated_cases.c.h" + #line 2359 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2242,7 +2363,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1583 "Python/bytecodes.c" + #line 1658 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2250,12 +2371,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2254 "Python/generated_cases.c.h" + #line 2375 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1591 "Python/bytecodes.c" + #line 1666 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2259 "Python/generated_cases.c.h" + #line 2380 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2263,17 +2384,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1597 "Python/bytecodes.c" + #line 1672 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2272 "Python/generated_cases.c.h" + #line 2393 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1602 "Python/bytecodes.c" + #line 1677 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2277 "Python/generated_cases.c.h" + #line 2398 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2282,25 +2403,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1608 "Python/bytecodes.c" + #line 1683 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2292 "Python/generated_cases.c.h" + #line 2413 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1616 "Python/bytecodes.c" + #line 1691 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2304 "Python/generated_cases.c.h" + #line 2425 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2311,7 +2432,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1630 "Python/bytecodes.c" + #line 1705 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2353,16 +2474,16 @@ } } } - #line 2357 "Python/generated_cases.c.h" + #line 2478 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1672 "Python/bytecodes.c" + #line 1747 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2366 "Python/generated_cases.c.h" + #line 2487 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2377,20 +2498,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1691 "Python/bytecodes.c" + #line 1766 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2388 "Python/generated_cases.c.h" + #line 2509 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1698 "Python/bytecodes.c" + #line 1773 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2394 "Python/generated_cases.c.h" + #line 2515 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2405,7 +2526,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1702 "Python/bytecodes.c" + #line 1777 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2428,7 +2549,7 @@ res = res2; res2 = NULL; } - #line 2432 "Python/generated_cases.c.h" + #line 2553 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2442,7 +2563,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1741 "Python/bytecodes.c" + #line 1816 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2476,9 +2597,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2480 "Python/generated_cases.c.h" + #line 2601 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1775 "Python/bytecodes.c" + #line 1850 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2487,12 +2608,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2491 "Python/generated_cases.c.h" + #line 2612 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1784 "Python/bytecodes.c" + #line 1859 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2496 "Python/generated_cases.c.h" + #line 2617 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2506,7 +2627,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1793 "Python/bytecodes.c" + #line 1868 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2519,7 +2640,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2523 "Python/generated_cases.c.h" + #line 2644 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2534,7 +2655,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1809 "Python/bytecodes.c" + #line 1884 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2547,7 +2668,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2551 "Python/generated_cases.c.h" + #line 2672 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2562,7 +2683,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1825 "Python/bytecodes.c" + #line 1900 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2589,7 +2710,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2593 "Python/generated_cases.c.h" + #line 2714 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2604,7 +2725,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1855 "Python/bytecodes.c" + #line 1930 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2614,7 +2735,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2618 "Python/generated_cases.c.h" + #line 2739 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2629,7 +2750,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1868 "Python/bytecodes.c" + #line 1943 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2641,7 +2762,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2645 "Python/generated_cases.c.h" + #line 2766 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2655,7 +2776,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1883 "Python/bytecodes.c" + #line 1958 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2679,7 +2800,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2683 "Python/generated_cases.c.h" + #line 2804 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2687,7 +2808,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1909 "Python/bytecodes.c" + #line 1984 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2713,7 +2834,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2717 "Python/generated_cases.c.h" + #line 2838 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2721,7 +2842,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1937 "Python/bytecodes.c" + #line 2012 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2739,7 +2860,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2743 "Python/generated_cases.c.h" + #line 2864 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2750,7 +2871,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1957 "Python/bytecodes.c" + #line 2032 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2789,7 +2910,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2793 "Python/generated_cases.c.h" + #line 2914 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2800,7 +2921,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1998 "Python/bytecodes.c" + #line 2073 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2810,7 +2931,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2814 "Python/generated_cases.c.h" + #line 2935 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2822,7 +2943,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2017 "Python/bytecodes.c" + #line 2092 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2833,14 +2954,20 @@ STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - #line 2839 "Python/generated_cases.c.h" + assert((oparg >> 5) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg >> 5); + #line 2960 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2030 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2844 "Python/generated_cases.c.h" + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res); + Py_DECREF(res); + if (res_bool < 0) goto pop_2_error; + res = res_bool ? Py_True : Py_False; + } + #line 2971 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2851,7 +2978,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2034 "Python/bytecodes.c" + #line 2115 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2862,7 +2989,8 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2866 "Python/generated_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 2994 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2873,7 +3001,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2048 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2888,7 +3016,8 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2892 "Python/generated_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 3021 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2899,19 +3028,20 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2066 "Python/bytecodes.c" + #line 2149 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); int eq = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + assert((oparg >> 5) == Py_EQ || (oparg >> 5) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2915 "Python/generated_cases.c.h" + // It's always a bool, so we don't care about oparg & 16. + #line 3045 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2922,14 +3052,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2080 "Python/bytecodes.c" + #line 2164 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2928 "Python/generated_cases.c.h" + #line 3058 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2082 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2933 "Python/generated_cases.c.h" + #line 3063 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2939,15 +3069,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2086 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2945 "Python/generated_cases.c.h" + #line 3075 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2088 "Python/bytecodes.c" + #line 2172 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2951 "Python/generated_cases.c.h" + #line 3081 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2958,12 +3088,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2093 "Python/bytecodes.c" + #line 2177 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2964 "Python/generated_cases.c.h" + #line 3094 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2095 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2971,10 +3101,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2975 "Python/generated_cases.c.h" + #line 3105 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2103 "Python/bytecodes.c" + #line 2187 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2983,7 +3113,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 2987 "Python/generated_cases.c.h" + #line 3117 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2993,21 +3123,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2114 "Python/bytecodes.c" + #line 2198 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3000 "Python/generated_cases.c.h" + #line 3130 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2117 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3007 "Python/generated_cases.c.h" + #line 3137 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2122 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3011 "Python/generated_cases.c.h" + #line 3141 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3016,15 +3146,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2126 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3023 "Python/generated_cases.c.h" + #line 3153 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2129 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3028 "Python/generated_cases.c.h" + #line 3158 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3033,25 +3163,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2133 "Python/bytecodes.c" + #line 2217 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3041 "Python/generated_cases.c.h" + #line 3171 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2139 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" JUMPBY(oparg); - #line 3050 "Python/generated_cases.c.h" + #line 3180 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2143 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3069,13 +3199,13 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3073 "Python/generated_cases.c.h" + #line 3203 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2174 "Python/bytecodes.c" + #line 2258 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); @@ -3085,107 +3215,81 @@ goto resume_with_error; } goto resume_frame; - #line 3089 "Python/generated_cases.c.h" + #line 3219 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2186 "Python/bytecodes.c" - if (Py_IsFalse(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsTrue(cond)) { - int err = PyObject_IsTrue(cond); - #line 3100 "Python/generated_cases.c.h" - Py_DECREF(cond); - #line 2192 "Python/bytecodes.c" - if (err == 0) { - JUMPBY(oparg); - } - else { - if (err < 0) goto pop_1_error; - } - } - #line 3110 "Python/generated_cases.c.h" + #line 2270 "Python/bytecodes.c" + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsFalse(cond)); + #line 3227 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2202 "Python/bytecodes.c" - if (Py_IsTrue(cond)) { - JUMPBY(oparg); - } - else if (!Py_IsFalse(cond)) { - int err = PyObject_IsTrue(cond); - #line 3123 "Python/generated_cases.c.h" - Py_DECREF(cond); - #line 2208 "Python/bytecodes.c" - if (err > 0) { - JUMPBY(oparg); - } - else { - if (err < 0) goto pop_1_error; - } - } - #line 3133 "Python/generated_cases.c.h" + #line 2275 "Python/bytecodes.c" + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsTrue(cond)); + #line 3237 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2218 "Python/bytecodes.c" + #line 2280 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3142 "Python/generated_cases.c.h" + #line 3246 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2220 "Python/bytecodes.c" + #line 2282 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3147 "Python/generated_cases.c.h" + #line 3251 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2225 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3159 "Python/generated_cases.c.h" + #line 3263 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2230 "Python/bytecodes.c" + #line 2292 "Python/bytecodes.c" } - #line 3163 "Python/generated_cases.c.h" + #line 3267 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2234 "Python/bytecodes.c" + #line 2296 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3176 "Python/generated_cases.c.h" + #line 3280 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2243 "Python/bytecodes.c" + #line 2305 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3189 "Python/generated_cases.c.h" + #line 3293 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3196,16 +3300,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2251 "Python/bytecodes.c" + #line 2313 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3205 "Python/generated_cases.c.h" + #line 3309 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2256 "Python/bytecodes.c" + #line 2318 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3213,7 +3317,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3217 "Python/generated_cases.c.h" + #line 3321 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3222,10 +3326,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2266 "Python/bytecodes.c" + #line 2328 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3229 "Python/generated_cases.c.h" + #line 3333 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3234,10 +3338,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2271 "Python/bytecodes.c" + #line 2333 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3241 "Python/generated_cases.c.h" + #line 3345 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3247,11 +3351,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2276 "Python/bytecodes.c" + #line 2338 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3255 "Python/generated_cases.c.h" + #line 3359 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3260,14 +3364,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2282 "Python/bytecodes.c" + #line 2344 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3267 "Python/generated_cases.c.h" + #line 3371 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2285 "Python/bytecodes.c" + #line 2347 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3271 "Python/generated_cases.c.h" + #line 3375 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3275,7 +3379,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2289 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3298,11 +3402,11 @@ if (iter == NULL) { goto error; } - #line 3302 "Python/generated_cases.c.h" + #line 3406 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2312 "Python/bytecodes.c" + #line 2374 "Python/bytecodes.c" } - #line 3306 "Python/generated_cases.c.h" + #line 3410 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3312,7 +3416,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2330 "Python/bytecodes.c" + #line 2392 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3344,7 +3448,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3348 "Python/generated_cases.c.h" + #line 3452 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3352,7 +3456,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2364 "Python/bytecodes.c" + #line 2426 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3378,14 +3482,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3382 "Python/generated_cases.c.h" + #line 3486 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2392 "Python/bytecodes.c" + #line 2454 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3406,7 +3510,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3410 "Python/generated_cases.c.h" + #line 3514 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3416,7 +3520,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2415 "Python/bytecodes.c" + #line 2477 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3437,7 +3541,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3441 "Python/generated_cases.c.h" + #line 3545 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3447,7 +3551,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2438 "Python/bytecodes.c" + #line 2500 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3466,7 +3570,7 @@ if (next == NULL) { goto error; } - #line 3470 "Python/generated_cases.c.h" + #line 3574 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3475,7 +3579,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2459 "Python/bytecodes.c" + #line 2521 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3491,14 +3595,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3495 "Python/generated_cases.c.h" + #line 3599 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2477 "Python/bytecodes.c" + #line 2539 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3521,16 +3625,16 @@ Py_DECREF(enter); goto error; } - #line 3525 "Python/generated_cases.c.h" + #line 3629 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2500 "Python/bytecodes.c" + #line 2562 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3534 "Python/generated_cases.c.h" + #line 3638 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3541,7 +3645,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2509 "Python/bytecodes.c" + #line 2571 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3567,16 +3671,16 @@ Py_DECREF(enter); goto error; } - #line 3571 "Python/generated_cases.c.h" + #line 3675 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2535 "Python/bytecodes.c" + #line 2597 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3580 "Python/generated_cases.c.h" + #line 3684 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3588,7 +3692,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2544 "Python/bytecodes.c" + #line 2606 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3609,7 +3713,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3613 "Python/generated_cases.c.h" + #line 3717 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3618,7 +3722,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2583 "Python/bytecodes.c" + #line 2645 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3628,7 +3732,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3632 "Python/generated_cases.c.h" + #line 3736 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3642,7 +3746,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2595 "Python/bytecodes.c" + #line 2657 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3659,7 +3763,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3663 "Python/generated_cases.c.h" + #line 3767 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3673,7 +3777,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2614 "Python/bytecodes.c" + #line 2676 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3683,7 +3787,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3687 "Python/generated_cases.c.h" + #line 3791 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3697,7 +3801,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2626 "Python/bytecodes.c" + #line 2688 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3711,7 +3815,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3715 "Python/generated_cases.c.h" + #line 3819 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3720,16 +3824,16 @@ } TARGET(KW_NAMES) { - #line 2642 "Python/bytecodes.c" + #line 2704 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3728 "Python/generated_cases.c.h" + #line 3832 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2648 "Python/bytecodes.c" + #line 2710 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3742,7 +3846,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3746 "Python/generated_cases.c.h" + #line 3850 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3752,7 +3856,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2694 "Python/bytecodes.c" + #line 2756 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3834,7 +3938,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3838 "Python/generated_cases.c.h" + #line 3942 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3846,7 +3950,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2782 "Python/bytecodes.c" + #line 2844 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3856,7 +3960,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3860 "Python/generated_cases.c.h" + #line 3964 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3865,7 +3969,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2794 "Python/bytecodes.c" + #line 2856 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3891,7 +3995,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3895 "Python/generated_cases.c.h" + #line 3999 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3899,7 +4003,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2822 "Python/bytecodes.c" + #line 2884 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3935,7 +4039,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3939 "Python/generated_cases.c.h" + #line 4043 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3943,7 +4047,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2860 "Python/bytecodes.c" + #line 2922 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3953,7 +4057,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3957 "Python/generated_cases.c.h" + #line 4061 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3966,7 +4070,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2872 "Python/bytecodes.c" + #line 2934 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3977,7 +4081,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3981 "Python/generated_cases.c.h" + #line 4085 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3991,7 +4095,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2886 "Python/bytecodes.c" + #line 2948 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4002,7 +4106,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4006 "Python/generated_cases.c.h" + #line 4110 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4015,7 +4119,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2900 "Python/bytecodes.c" + #line 2962 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4065,12 +4169,12 @@ frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); goto start_frame; - #line 4069 "Python/generated_cases.c.h" + #line 4173 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2952 "Python/bytecodes.c" + #line 3014 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4078,7 +4182,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4082 "Python/generated_cases.c.h" + #line 4186 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4088,7 +4192,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2962 "Python/bytecodes.c" + #line 3024 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4110,7 +4214,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4114 "Python/generated_cases.c.h" + #line 4218 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4124,7 +4228,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2987 "Python/bytecodes.c" + #line 3049 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4152,7 +4256,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4156 "Python/generated_cases.c.h" + #line 4260 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4166,7 +4270,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3018 "Python/bytecodes.c" + #line 3080 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4198,7 +4302,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4202 "Python/generated_cases.c.h" + #line 4306 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4212,7 +4316,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3053 "Python/bytecodes.c" + #line 3115 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4244,7 +4348,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4248 "Python/generated_cases.c.h" + #line 4352 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4258,7 +4362,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3088 "Python/bytecodes.c" + #line 3150 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4283,7 +4387,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4287 "Python/generated_cases.c.h" + #line 4391 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4296,7 +4400,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3115 "Python/bytecodes.c" + #line 3177 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4323,7 +4427,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4327 "Python/generated_cases.c.h" + #line 4431 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4335,7 +4439,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3145 "Python/bytecodes.c" + #line 3207 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4353,14 +4457,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4357 "Python/generated_cases.c.h" + #line 4461 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3165 "Python/bytecodes.c" + #line 3227 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4391,7 +4495,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4395 "Python/generated_cases.c.h" + #line 4499 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4404,7 +4508,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3199 "Python/bytecodes.c" + #line 3261 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4433,7 +4537,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4437 "Python/generated_cases.c.h" + #line 4541 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4446,7 +4550,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3231 "Python/bytecodes.c" + #line 3293 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4475,7 +4579,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4479 "Python/generated_cases.c.h" + #line 4583 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4488,7 +4592,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3263 "Python/bytecodes.c" + #line 3325 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4516,7 +4620,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4520 "Python/generated_cases.c.h" + #line 4624 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4526,9 +4630,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3294 "Python/bytecodes.c" + #line 3356 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4532 "Python/generated_cases.c.h" + #line 4636 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4537,7 +4641,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3298 "Python/bytecodes.c" + #line 3360 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4599,14 +4703,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4603 "Python/generated_cases.c.h" + #line 4707 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3360 "Python/bytecodes.c" + #line 3422 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4610 "Python/generated_cases.c.h" + #line 4714 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4617,7 +4721,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3366 "Python/bytecodes.c" + #line 3428 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4629,7 +4733,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4633 "Python/generated_cases.c.h" + #line 4737 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4637,7 +4741,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3380 "Python/bytecodes.c" + #line 3442 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4662,14 +4766,14 @@ default: Py_UNREACHABLE(); } - #line 4666 "Python/generated_cases.c.h" + #line 4770 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3407 "Python/bytecodes.c" + #line 3469 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4690,7 +4794,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4694 "Python/generated_cases.c.h" + #line 4798 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4698,15 +4802,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3430 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4704 "Python/generated_cases.c.h" + #line 4808 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3432 "Python/bytecodes.c" + #line 3494 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4710 "Python/generated_cases.c.h" + #line 4814 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4716,14 +4820,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3436 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4727 "Python/generated_cases.c.h" + #line 4831 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4731,7 +4835,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3445 "Python/bytecodes.c" + #line 3507 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4742,7 +4846,7 @@ else { res = value; } - #line 4746 "Python/generated_cases.c.h" + #line 4850 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4751,12 +4855,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3458 "Python/bytecodes.c" + #line 3520 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4760 "Python/generated_cases.c.h" + #line 4864 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4765,10 +4869,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3465 "Python/bytecodes.c" + #line 3527 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4772 "Python/generated_cases.c.h" + #line 4876 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4780,7 +4884,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3470 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4795,12 +4899,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4799 "Python/generated_cases.c.h" + #line 4903 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3485 "Python/bytecodes.c" + #line 3547 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4804 "Python/generated_cases.c.h" + #line 4908 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4810,16 +4914,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3490 "Python/bytecodes.c" + #line 3552 "Python/bytecodes.c" assert(oparg >= 2); - #line 4816 "Python/generated_cases.c.h" + #line 4920 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3494 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4831,54 +4935,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4835 "Python/generated_cases.c.h" + #line 4939 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3508 "Python/bytecodes.c" + #line 3570 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4841 "Python/generated_cases.c.h" + #line 4945 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3512 "Python/bytecodes.c" + #line 3574 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4848 "Python/generated_cases.c.h" + #line 4952 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3517 "Python/bytecodes.c" + #line 3579 "Python/bytecodes.c" PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) goto error; - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = err*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4863 "Python/generated_cases.c.h" + #line 4964 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3528 "Python/bytecodes.c" + #line 3587 "Python/bytecodes.c" PyObject *cond = POP(); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) goto error; - _Py_CODEUNIT *here = next_instr-1; - assert(err == 0 || err == 1); - int offset = (1-err)*oparg; + assert(PyBool_Check(cond)); + _Py_CODEUNIT *here = next_instr - 1; + int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4877 "Python/generated_cases.c.h" + #line 4975 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3539 "Python/bytecodes.c" + #line 3595 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4890,12 +4988,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4894 "Python/generated_cases.c.h" + #line 4992 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3553 "Python/bytecodes.c" + #line 3609 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4904,33 +5002,33 @@ } else { Py_DECREF(value); - offset = oparg; + offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4911 "Python/generated_cases.c.h" + #line 5009 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3567 "Python/bytecodes.c" + #line 3623 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4922 "Python/generated_cases.c.h" + #line 5020 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3575 "Python/bytecodes.c" + #line 3631 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4929 "Python/generated_cases.c.h" + #line 5027 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3580 "Python/bytecodes.c" + #line 3636 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4936 "Python/generated_cases.c.h" + #line 5034 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 991006ceb182a6..5c7de77deba2d6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -82,6 +82,20 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case UNARY_NOT: return 1; + case TO_BOOL: + return 1; + case TO_BOOL_BOOL: + return 1; + case TO_BOOL_INT: + return 1; + case TO_BOOL_LIST: + return 1; + case TO_BOOL_NONE: + return 1; + case TO_BOOL_STR: + return 1; + case TO_BOOL_ALWAYS_TRUE: + return 1; case UNARY_INVERT: return 1; case BINARY_OP_MULTIPLY_INT: @@ -508,6 +522,20 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case UNARY_NOT: return 1; + case TO_BOOL: + return 1; + case TO_BOOL_BOOL: + return 1; + case TO_BOOL_INT: + return 1; + case TO_BOOL_LIST: + return 1; + case TO_BOOL_NONE: + return 1; + case TO_BOOL_STR: + return 1; + case TO_BOOL_ALWAYS_TRUE: + return 1; case UNARY_INVERT: return 1; case BINARY_OP_MULTIPLY_INT: @@ -886,7 +914,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC00, INSTR_FMT_IXC000 }; #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) @@ -940,6 +968,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 }, [UNARY_NEGATIVE] = { true, INSTR_FMT_IX, 0 }, [UNARY_NOT] = { true, INSTR_FMT_IX, 0 }, + [TO_BOOL] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_INT] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_NONE] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_STR] = { true, INSTR_FMT_IXC00, 0 }, + [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, 0 }, [UNARY_INVERT] = { true, INSTR_FMT_IX, 0 }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC, 0 }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC, 0 }, @@ -1139,6 +1174,12 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, + [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } }, + [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } }, + [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } }, + [TO_BOOL_NONE] = { .nuops = 1, .uops = { { TO_BOOL_NONE, 0, 0 } } }, + [TO_BOOL_STR] = { .nuops = 1, .uops = { { TO_BOOL_STR, 0, 0 } } }, + [TO_BOOL_ALWAYS_TRUE] = { .nuops = 1, .uops = { { TO_BOOL_ALWAYS_TRUE, 2, 1 } } }, [UNARY_INVERT] = { .nuops = 1, .uops = { { UNARY_INVERT, 0, 0 } } }, [BINARY_OP_MULTIPLY_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_MULTIPLY_INT, 0, 0 } } }, [BINARY_OP_ADD_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_ADD_INT, 0, 0 } } }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 8561d9d4a3638e..1a1ad97e00135a 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -5,49 +5,49 @@ static void *opcode_targets[256] = { &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, &&TARGET_END_SEND, - &&TARGET_BINARY_OP_MULTIPLY_INT, - &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_TO_BOOL, + &&TARGET_TO_BOOL_ALWAYS_TRUE, + &&TARGET_TO_BOOL_BOOL, &&TARGET_NOP, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_TO_BOOL_INT, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, - &&TARGET_BINARY_OP_ADD_FLOAT, - &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_TO_BOOL_LIST, + &&TARGET_TO_BOOL_NONE, &&TARGET_UNARY_INVERT, &&TARGET_EXIT_INIT_CHECK, &&TARGET_RESERVED, - &&TARGET_BINARY_OP_ADD_UNICODE, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, - &&TARGET_BINARY_SUBSCR_DICT, - &&TARGET_BINARY_SUBSCR_GETITEM, - &&TARGET_BINARY_SUBSCR_LIST_INT, - &&TARGET_BINARY_SUBSCR_TUPLE_INT, + &&TARGET_TO_BOOL_STR, + &&TARGET_BINARY_OP_MULTIPLY_INT, + &&TARGET_BINARY_OP_ADD_INT, + &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_MAKE_FUNCTION, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT, + &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_SEND_GEN, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_BINARY_SUBSCR_DICT, + &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_FORMAT_SIMPLE, &&TARGET_FORMAT_WITH_SPEC, - &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_LOAD_SUPER_ATTR_ATTR, + &&TARGET_BINARY_SUBSCR_LIST_INT, + &&TARGET_BINARY_SUBSCR_TUPLE_INT, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_SEND_GEN, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_SUBSCR, + &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_SUPER_ATTR_ATTR, &&TARGET_LOAD_SUPER_ATTR_METHOD, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_GET_ITER, + &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_LOAD_ATTR_WITH_HINT, - &&TARGET_STORE_SUBSCR, - &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_GET_ITER, - &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_BUILD_CLASS, &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, - &&TARGET_LOAD_ASSERTION_ERROR, - &&TARGET_RETURN_GENERATOR, - &&TARGET_COMPARE_OP_STR, - &&TARGET_FOR_ITER_LIST, - &&TARGET_FOR_ITER_TUPLE, - &&TARGET_FOR_ITER_RANGE, - &&TARGET_FOR_ITER_GEN, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_RETURN_VALUE, - &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_COMPARE_OP_STR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_FOR_ITER_LIST, &&TARGET_LOAD_LOCALS, - &&TARGET_CALL_NO_KW_STR_1, + &&TARGET_FOR_ITER_TUPLE, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, - &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_BUILTIN_CLASS, - &&TARGET_CALL_NO_KW_BUILTIN_O, + &&TARGET_FOR_ITER_RANGE, + &&TARGET_FOR_ITER_GEN, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,11 +131,11 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, @@ -147,26 +147,26 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_CALL_NO_KW_LEN, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_CALL_NO_KW_ISINSTANCE, - &&TARGET_CALL_NO_KW_LIST_APPEND, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, + &&TARGET_CALL_NO_KW_STR_1, + &&TARGET_CALL_NO_KW_TUPLE_1, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_CONVERT_VALUE, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_CALL_NO_KW_BUILTIN_O, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_LEN, + &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_LOAD_FAST_LOAD_FAST, &&TARGET_STORE_FAST_LOAD_FAST, &&TARGET_STORE_FAST_STORE_FAST, @@ -177,12 +177,12 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, &&TARGET_LOAD_FROM_DICT_OR_DEREF, &&TARGET_SET_FUNCTION_ATTRIBUTE, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_CALL_NO_KW_LIST_APPEND, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, + &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index 3f51432a63af1f..22c58e2c46fc36 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -107,6 +107,8 @@ _Py_GetSpecializationStats(void) { err += add_stat_dict(stats, COMPARE_OP, "compare_op"); err += add_stat_dict(stats, UNPACK_SEQUENCE, "unpack_sequence"); err += add_stat_dict(stats, FOR_ITER, "for_iter"); + err += add_stat_dict(stats, TO_BOOL, "to_bool"); + err += add_stat_dict(stats, SEND, "send"); if (err < 0) { Py_DECREF(stats); return NULL; @@ -127,9 +129,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats) /* Mark some opcodes as specializable for stats, * even though we don't specialize them yet. */ fprintf(out, "opcode[%d].specializable : 1\n", BINARY_SLICE); - fprintf(out, "opcode[%d].specializable : 1\n", COMPARE_OP); fprintf(out, "opcode[%d].specializable : 1\n", STORE_SLICE); - fprintf(out, "opcode[%d].specializable : 1\n", SEND); for (int i = 0; i < 256; i++) { if (_PyOpcode_Caches[i]) { fprintf(out, "opcode[%d].specializable : 1\n", i); @@ -447,6 +447,18 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_UNPACK_SEQUENCE_ITERATOR 9 #define SPEC_FAIL_UNPACK_SEQUENCE_SEQUENCE 10 +// TO_BOOL +#define SPEC_FAIL_TO_BOOL_BYTEARRAY 9 +#define SPEC_FAIL_TO_BOOL_BYTES 10 +#define SPEC_FAIL_TO_BOOL_DICT 11 +#define SPEC_FAIL_TO_BOOL_FLOAT 12 +#define SPEC_FAIL_TO_BOOL_MAPPING 13 +#define SPEC_FAIL_TO_BOOL_MEMORY_VIEW 14 +#define SPEC_FAIL_TO_BOOL_NUMBER 15 +#define SPEC_FAIL_TO_BOOL_SEQUENCE 16 +#define SPEC_FAIL_TO_BOOL_SET 17 +#define SPEC_FAIL_TO_BOOL_TUPLE 18 + static int function_kind(PyCodeObject *code); static bool function_check_args(PyObject *o, int expected_argcount, int opcode); static uint32_t function_get_version(PyObject *o, int opcode); @@ -2047,6 +2059,8 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); + // All of these specializations compute boolean values, so they're all valid + // regardless of the fifth-lowest oparg bit. _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); if (Py_TYPE(lhs) != Py_TYPE(rhs)) { SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); @@ -2067,7 +2081,7 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, } } if (PyUnicode_CheckExact(lhs)) { - int cmp = oparg >> 4; + int cmp = oparg >> 5; if (cmp != Py_EQ && cmp != Py_NE) { SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING); goto failure; @@ -2284,6 +2298,99 @@ _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr) cache->counter = adaptive_counter_cooldown(); } +void +_Py_Specialize_ToBool(PyObject *value, _Py_CODEUNIT *instr) +{ + assert(ENABLE_SPECIALIZATION); + assert(_PyOpcode_Caches[TO_BOOL] == INLINE_CACHE_ENTRIES_TO_BOOL); + _PyToBoolCache *cache = (_PyToBoolCache *)(instr + 1); + if (PyBool_Check(value)) { + instr->op.code = TO_BOOL_BOOL; + goto success; + } + if (PyLong_CheckExact(value)) { + instr->op.code = TO_BOOL_INT; + goto success; + } + if (PyList_CheckExact(value)) { + instr->op.code = TO_BOOL_LIST; + goto success; + } + if (Py_IsNone(value)) { + instr->op.code = TO_BOOL_NONE; + goto success; + } + if (PyUnicode_CheckExact(value)) { + instr->op.code = TO_BOOL_STR; + goto success; + } + if (PyType_HasFeature(Py_TYPE(value), Py_TPFLAGS_HEAPTYPE)) { + PyNumberMethods *nb = Py_TYPE(value)->tp_as_number; + if (nb && nb->nb_bool) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_NUMBER); + goto failure; + } + PyMappingMethods *mp = Py_TYPE(value)->tp_as_mapping; + if (mp && mp->mp_length) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_MAPPING); + goto failure; + } + PySequenceMethods *sq = Py_TYPE(value)->tp_as_sequence; + if (sq && sq->sq_length) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_SEQUENCE); + goto failure; + } + if (!PyUnstable_Type_AssignVersionTag(Py_TYPE(value))) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_OUT_OF_VERSIONS); + goto failure; + } + uint32_t version = Py_TYPE(value)->tp_version_tag; + instr->op.code = TO_BOOL_ALWAYS_TRUE; + write_u32(cache->version, version); + assert(version); + goto success; + } +#ifdef Py_STATS + if (PyByteArray_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_BYTEARRAY); + goto failure; + } + if (PyBytes_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_BYTES); + goto failure; + } + if (PyDict_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_DICT); + goto failure; + } + if (PyFloat_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_FLOAT); + goto failure; + } + if (PyMemoryView_Check(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_MEMORY_VIEW); + goto failure; + } + if (PyAnySet_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_SET); + goto failure; + } + if (PyTuple_CheckExact(value)) { + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_TO_BOOL_TUPLE); + goto failure; + } + SPECIALIZATION_FAIL(TO_BOOL, SPEC_FAIL_OTHER); +#endif +failure: + STAT_INC(TO_BOOL, failure); + instr->op.code = TO_BOOL; + cache->counter = adaptive_counter_backoff(cache->counter); + return; +success: + STAT_INC(TO_BOOL, success); + cache->counter = adaptive_counter_cooldown(); +} + /* Code init cleanup. * CALL_NO_KW_ALLOC_AND_ENTER_INIT will set up * the frame to execute the EXIT_INIT_CHECK From cea9d4ea82abcb2c6f1d83a2fe819859da4bbda4 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 29 Jun 2023 16:14:09 -0700 Subject: [PATCH 187/446] GH-106152: Add PY_THROW event to cProfile (GH-106161) --- Lib/test/test_cprofile.py | 20 +++++++++++++++++++ ...-06-27-23-22-37.gh-issue-106152.ya5jBT.rst | 1 + Modules/_lsprof.c | 1 + 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 484b8f8e3a365c..3056fe84dac5dd 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -66,6 +66,26 @@ def test_second_profiler(self): self.assertRaises(ValueError, pr2.enable) pr.disable() + def test_throw(self): + """ + gh-106152 + generator.throw() should trigger a call in cProfile + In the any() call below, there should be two entries for the generator: + * one for the call to __next__ which gets a True and terminates any + * one when the generator is garbage collected which will effectively + do a throw. + """ + pr = self.profilerclass() + pr.enable() + any(a == 1 for a in (1, 2)) + pr.disable() + pr.create_stats() + + for func, (cc, nc, _, _, _) in pr.stats.items(): + if func[2] == "": + self.assertEqual(cc, 2) + self.assertEqual(nc, 2) + class TestCommandLine(unittest.TestCase): def test_sort(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst new file mode 100644 index 00000000000000..da9d2605f46294 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst @@ -0,0 +1 @@ +Added PY_THROW event hook for :mod:`cProfile` for generators diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 1c84f66ee6f579..257de4387c0ab9 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -678,6 +678,7 @@ static const struct { } callback_table[] = { {PY_MONITORING_EVENT_PY_START, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"}, + {PY_MONITORING_EVENT_PY_THROW, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"}, From e7bc8d16364bde54487eab349a29d58345e35f28 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 29 Jun 2023 17:20:49 -0700 Subject: [PATCH 188/446] gh-106210 Remove Emscripten import trampoline (#106211) It's no longer necessary. Co-authored-by: Brett Cannon --- .../2023-06-28-13-19-20.gh-issue-106210.oE7VMn.rst | 1 + Python/import.c | 14 ++------------ Python/importdl.c | 2 +- Python/importdl.h | 6 ------ 4 files changed, 4 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-28-13-19-20.gh-issue-106210.oE7VMn.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-28-13-19-20.gh-issue-106210.oE7VMn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-28-13-19-20.gh-issue-106210.oE7VMn.rst new file mode 100644 index 00000000000000..fde549d21e440a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-28-13-19-20.gh-issue-106210.oE7VMn.rst @@ -0,0 +1 @@ +Removed Emscripten import trampoline as it was no longer necessary for Pyodide. diff --git a/Python/import.c b/Python/import.c index b3699bdec994d6..324fe3812bdd49 100644 --- a/Python/import.c +++ b/Python/import.c @@ -839,16 +839,6 @@ _PyImport_ClearExtension(PyObject *name, PyObject *filename) } -/*******************/ - -#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) -#include -EM_JS(PyObject*, _PyImport_InitFunc_TrampolineCall, (PyModInitFunction func), { - return wasmTable.get(func)(); -}); -#endif // __EMSCRIPTEN__ && PY_CALL_TRAMPOLINE - - /*****************************/ /* single-phase init modules */ /*****************************/ @@ -1285,7 +1275,7 @@ import_find_extension(PyThreadState *tstate, PyObject *name, else { if (def->m_base.m_init == NULL) return NULL; - mod = _PyImport_InitFunc_TrampolineCall(def->m_base.m_init); + mod = def->m_base.m_init(); if (mod == NULL) return NULL; if (PyObject_SetItem(modules, name, mod) == -1) { @@ -1400,7 +1390,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) /* Cannot re-init internal module ("sys" or "builtins") */ return import_add_module(tstate, name); } - mod = _PyImport_InitFunc_TrampolineCall(*p->initfunc); + mod = (*p->initfunc)(); if (mod == NULL) { return NULL; } diff --git a/Python/importdl.c b/Python/importdl.c index 3a3a30ddbdcdb5..eb6b808ecba1d5 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -166,7 +166,7 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) /* Package context is needed for single-phase init */ oldcontext = _PyImport_SwapPackageContext(newcontext); - m = _PyImport_InitFunc_TrampolineCall(p0); + m = p0(); _PyImport_SwapPackageContext(oldcontext); if (m == NULL) { diff --git a/Python/importdl.h b/Python/importdl.h index 26d18b626df052..9171adc2770689 100644 --- a/Python/importdl.h +++ b/Python/importdl.h @@ -12,12 +12,6 @@ extern PyObject *_PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *); typedef PyObject *(*PyModInitFunction)(void); -#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) -extern PyObject *_PyImport_InitFunc_TrampolineCall(PyModInitFunction func); -#else -#define _PyImport_InitFunc_TrampolineCall(func) (func)() -#endif - /* Max length of module suffix searched for -- accommodates "module.slb" */ #define MAXSUFFIXSIZE 12 From 8c5f74fc89e35827c52753fe620b32207d537319 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 03:05:01 +0200 Subject: [PATCH 189/446] gh-106023: Update code using _PyObject_FastCall() (#106257) Replace _PyObject_FastCall() calls with PyObject_Vectorcall(). --- Modules/_elementtree.c | 22 +- Modules/_functoolsmodule.c | 21 +- Objects/typeobject.c | 3 +- Parser/pegen.c | 4 +- Python/bytecodes.c | 1 - Python/ceval.c | 27 +- Python/executor_cases.c.h | 270 +++++++++---------- Python/generated_cases.c.h | 530 ++++++++++++++++++------------------- Python/pythonrun.c | 7 +- Python/sysmodule.c | 2 +- 10 files changed, 434 insertions(+), 453 deletions(-) diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 21a6e4e5b20264..2a0eac4d2f8085 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -882,7 +882,6 @@ LOCAL(PyObject *) deepcopy(elementtreestate *st, PyObject *object, PyObject *memo) { /* do a deep copy of the given object */ - PyObject *stack[2]; /* Fast paths */ if (object == Py_None || PyUnicode_CheckExact(object)) { @@ -917,9 +916,8 @@ deepcopy(elementtreestate *st, PyObject *object, PyObject *memo) return NULL; } - stack[0] = object; - stack[1] = memo; - return _PyObject_FastCall(st->deepcopy_obj, stack, 2); + PyObject *args[2] = {object, memo}; + return PyObject_Vectorcall(st->deepcopy_obj, args, 2, NULL); } @@ -2852,14 +2850,14 @@ treebuilder_handle_pi(TreeBuilderObject* self, PyObject* target, PyObject* text) { PyObject* pi; PyObject* this; - PyObject* stack[2] = {target, text}; if (treebuilder_flush_data(self) < 0) { return NULL; } if (self->pi_factory) { - pi = _PyObject_FastCall(self->pi_factory, stack, 2); + PyObject* args[2] = {target, text}; + pi = PyObject_Vectorcall(self->pi_factory, args, 2, NULL); if (!pi) { return NULL; } @@ -3372,7 +3370,6 @@ expat_start_ns_handler(XMLParserObject* self, const XML_Char* prefix_in, PyObject* res = NULL; PyObject* uri; PyObject* prefix; - PyObject* stack[2]; if (PyErr_Occurred()) return; @@ -3411,9 +3408,8 @@ expat_start_ns_handler(XMLParserObject* self, const XML_Char* prefix_in, return; } - stack[0] = prefix; - stack[1] = uri; - res = _PyObject_FastCall(self->handle_start_ns, stack, 2); + PyObject* args[2] = {prefix, uri}; + res = PyObject_Vectorcall(self->handle_start_ns, args, 2, NULL); Py_DECREF(uri); Py_DECREF(prefix); } @@ -3551,7 +3547,6 @@ expat_pi_handler(XMLParserObject* self, const XML_Char* target_in, PyObject* pi_target; PyObject* data; PyObject* res; - PyObject* stack[2]; if (PyErr_Occurred()) return; @@ -3581,9 +3576,8 @@ expat_pi_handler(XMLParserObject* self, const XML_Char* target_in, if (!data) goto error; - stack[0] = pi_target; - stack[1] = data; - res = _PyObject_FastCall(self->handle_pi, stack, 2); + PyObject* args[2] = {pi_target, data}; + res = PyObject_Vectorcall(self->handle_pi, args, 2, NULL); Py_XDECREF(res); Py_DECREF(data); Py_DECREF(pi_target); diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index aa566c31cc1eaa..c987485e66a48a 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -594,21 +594,15 @@ keyobject_call(keyobject *ko, PyObject *args, PyObject *kwds) static PyObject * keyobject_richcompare(PyObject *ko, PyObject *other, int op) { - PyObject *res; - PyObject *x; - PyObject *y; - PyObject *compare; - PyObject *answer; - PyObject* stack[2]; - if (!Py_IS_TYPE(other, Py_TYPE(ko))) { PyErr_Format(PyExc_TypeError, "other argument must be K instance"); return NULL; } - compare = ((keyobject *) ko)->cmp; + + PyObject *compare = ((keyobject *) ko)->cmp; assert(compare != NULL); - x = ((keyobject *) ko)->object; - y = ((keyobject *) other)->object; + PyObject *x = ((keyobject *) ko)->object; + PyObject *y = ((keyobject *) other)->object; if (!x || !y){ PyErr_Format(PyExc_AttributeError, "object"); return NULL; @@ -617,14 +611,13 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op) /* Call the user's comparison function and translate the 3-way * result into true or false (or error). */ - stack[0] = x; - stack[1] = y; - res = _PyObject_FastCall(compare, stack, 2); + PyObject* args[2] = {x, y}; + PyObject *res = PyObject_Vectorcall(compare, args, 2, NULL); if (res == NULL) { return NULL; } - answer = PyObject_RichCompare(res, _PyLong_GetZero(), op); + PyObject *answer = PyObject_RichCompare(res, _PyLong_GetZero(), op); Py_DECREF(res); return answer; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e3769cee2c3972..cc389bc3d6fa1b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10013,7 +10013,8 @@ static int type_new_init_subclass(PyTypeObject *type, PyObject *kwds) { PyObject *args[2] = {(PyObject *)type, (PyObject *)type}; - PyObject *super = _PyObject_FastCall((PyObject *)&PySuper_Type, args, 2); + PyObject *super = PyObject_Vectorcall((PyObject *)&PySuper_Type, + args, 2, NULL); if (super == NULL) { return -1; } diff --git a/Parser/pegen.c b/Parser/pegen.c index b9894dd0acc546..885d423fca66a9 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -465,7 +465,6 @@ _PyPegen_new_identifier(Parser *p, const char *n) identifier; if so, normalize to NFKC. */ if (!PyUnicode_IS_ASCII(id)) { - PyObject *id2; if (!init_normalization(p)) { Py_DECREF(id); @@ -478,12 +477,13 @@ _PyPegen_new_identifier(Parser *p, const char *n) goto error; } PyObject *args[2] = {form, id}; - id2 = _PyObject_FastCall(p->normalize, args, 2); + PyObject *id2 = PyObject_Vectorcall(p->normalize, args, 2, NULL); Py_DECREF(id); Py_DECREF(form); if (!id2) { goto error; } + if (!PyUnicode_Check(id2)) { PyErr_Format(PyExc_TypeError, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index cd23e6624706fa..8aab7ebc5cf0cb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -8,7 +8,6 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_call.h" // _PyObject_FastCallDictTstate() #include "pycore_ceval.h" // _PyEval_SignalAsyncExc() #include "pycore_code.h" #include "pycore_function.h" diff --git a/Python/ceval.c b/Python/ceval.c index 65b6f2481665de..2010e9e6e7a1c6 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4,7 +4,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_call.h" // _PyObject_FastCallDictTstate() +#include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SignalAsyncExc() #include "pycore_code.h" #include "pycore_function.h" @@ -2431,40 +2431,37 @@ static PyObject * import_name(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name, PyObject *fromlist, PyObject *level) { - PyObject *import_func, *res; - PyObject* stack[5]; - - import_func = _PyDict_GetItemWithError(frame->f_builtins, &_Py_ID(__import__)); + PyObject *import_func = _PyDict_GetItemWithError(frame->f_builtins, + &_Py_ID(__import__)); if (import_func == NULL) { if (!_PyErr_Occurred(tstate)) { _PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found"); } return NULL; } + PyObject *locals = frame->f_locals; + if (locals == NULL) { + locals = Py_None; + } + /* Fast path for not overloaded __import__. */ if (_PyImport_IsDefaultImportFunc(tstate->interp, import_func)) { int ilevel = _PyLong_AsInt(level); if (ilevel == -1 && _PyErr_Occurred(tstate)) { return NULL; } - res = PyImport_ImportModuleLevelObject( + return PyImport_ImportModuleLevelObject( name, frame->f_globals, - locals == NULL ? Py_None :locals, + locals, fromlist, ilevel); - return res; } + PyObject* args[5] = {name, frame->f_globals, locals, fromlist, level}; Py_INCREF(import_func); - - stack[0] = name; - stack[1] = frame->f_globals; - stack[2] = locals == NULL ? Py_None : locals; - stack[3] = fromlist; - stack[4] = level; - res = _PyObject_FastCall(import_func, stack, 5); + PyObject *res = PyObject_Vectorcall(import_func, args, 5, NULL); Py_DECREF(import_func); return res; } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ea932232d7522a..ccef2736b7120b 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9,7 +9,7 @@ case LOAD_FAST: { PyObject *value; - #line 189 "Python/bytecodes.c" + #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -21,7 +21,7 @@ case LOAD_FAST_AND_CLEAR: { PyObject *value; - #line 195 "Python/bytecodes.c" + #line 194 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -33,7 +33,7 @@ case LOAD_CONST: { PyObject *value; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 40 "Python/executor_cases.c.h" @@ -44,7 +44,7 @@ case STORE_FAST: { PyObject *value = stack_pointer[-1]; - #line 215 "Python/bytecodes.c" + #line 214 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 50 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -53,7 +53,7 @@ case POP_TOP: { PyObject *value = stack_pointer[-1]; - #line 238 "Python/bytecodes.c" + #line 237 "Python/bytecodes.c" #line 58 "Python/executor_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -62,7 +62,7 @@ case PUSH_NULL: { PyObject *res; - #line 242 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" res = NULL; #line 68 "Python/executor_cases.c.h" STACK_GROW(1); @@ -73,7 +73,7 @@ case END_SEND: { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 261 "Python/bytecodes.c" + #line 260 "Python/bytecodes.c" Py_DECREF(receiver); #line 79 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -84,11 +84,11 @@ case UNARY_NEGATIVE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 276 "Python/bytecodes.c" + #line 275 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 90 "Python/executor_cases.c.h" Py_DECREF(value); - #line 278 "Python/bytecodes.c" + #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 94 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -98,7 +98,7 @@ case UNARY_NOT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 282 "Python/bytecodes.c" + #line 281 "Python/bytecodes.c" assert(PyBool_Check(value)); res = Py_IsFalse(value) ? Py_True : Py_False; #line 105 "Python/executor_cases.c.h" @@ -108,7 +108,7 @@ case TO_BOOL_BOOL: { PyObject *value = stack_pointer[-1]; - #line 314 "Python/bytecodes.c" + #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); #line 115 "Python/executor_cases.c.h" @@ -118,7 +118,7 @@ case TO_BOOL_INT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 319 "Python/bytecodes.c" + #line 318 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value)) { @@ -128,7 +128,7 @@ else { #line 130 "Python/executor_cases.c.h" Py_DECREF(value); - #line 327 "Python/bytecodes.c" + #line 326 "Python/bytecodes.c" res = Py_True; } #line 135 "Python/executor_cases.c.h" @@ -139,7 +139,7 @@ case TO_BOOL_LIST: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 332 "Python/bytecodes.c" + #line 331 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; @@ -152,7 +152,7 @@ case TO_BOOL_NONE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 339 "Python/bytecodes.c" + #line 338 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); @@ -165,7 +165,7 @@ case TO_BOOL_STR: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 346 "Python/bytecodes.c" + #line 345 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (value == &_Py_STR(empty)) { @@ -176,7 +176,7 @@ assert(Py_SIZE(value)); #line 178 "Python/executor_cases.c.h" Py_DECREF(value); - #line 355 "Python/bytecodes.c" + #line 354 "Python/bytecodes.c" res = Py_True; } #line 183 "Python/executor_cases.c.h" @@ -188,14 +188,14 @@ PyObject *value = stack_pointer[-1]; PyObject *res; uint32_t version = operand; - #line 360 "Python/bytecodes.c" + #line 359 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); #line 197 "Python/executor_cases.c.h" Py_DECREF(value); - #line 365 "Python/bytecodes.c" + #line 364 "Python/bytecodes.c" res = Py_True; #line 201 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -205,11 +205,11 @@ case UNARY_INVERT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 369 "Python/bytecodes.c" + #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 211 "Python/executor_cases.c.h" Py_DECREF(value); - #line 371 "Python/bytecodes.c" + #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 215 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -219,7 +219,7 @@ case _GUARD_BOTH_INT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 387 "Python/bytecodes.c" + #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 226 "Python/executor_cases.c.h" @@ -230,7 +230,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 392 "Python/bytecodes.c" + #line 391 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -246,7 +246,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 400 "Python/bytecodes.c" + #line 399 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -262,7 +262,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 408 "Python/bytecodes.c" + #line 407 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -277,7 +277,7 @@ case _GUARD_BOTH_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 423 "Python/bytecodes.c" + #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 284 "Python/executor_cases.c.h" @@ -288,7 +288,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 428 "Python/bytecodes.c" + #line 427 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -304,7 +304,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 436 "Python/bytecodes.c" + #line 435 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -320,7 +320,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 444 "Python/bytecodes.c" + #line 443 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -335,7 +335,7 @@ case _GUARD_BOTH_UNICODE: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 459 "Python/bytecodes.c" + #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 342 "Python/executor_cases.c.h" @@ -346,7 +346,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 464 "Python/bytecodes.c" + #line 463 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -363,7 +363,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 534 "Python/bytecodes.c" + #line 533 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -387,7 +387,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 549 "Python/bytecodes.c" + #line 548 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -409,7 +409,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 564 "Python/bytecodes.c" + #line 563 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -433,7 +433,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 580 "Python/bytecodes.c" + #line 579 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -457,7 +457,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 596 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -468,7 +468,7 @@ #line 469 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 604 "Python/bytecodes.c" + #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -483,7 +483,7 @@ case LIST_APPEND: { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 636 "Python/bytecodes.c" + #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 489 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -493,11 +493,11 @@ case SET_ADD: { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 640 "Python/bytecodes.c" + #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 499 "Python/executor_cases.c.h" Py_DECREF(v); - #line 642 "Python/bytecodes.c" + #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; #line 503 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -508,7 +508,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 671 "Python/bytecodes.c" + #line 670 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -534,7 +534,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 690 "Python/bytecodes.c" + #line 689 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -548,13 +548,13 @@ case DELETE_SUBSCR: { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 698 "Python/bytecodes.c" + #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 555 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 701 "Python/bytecodes.c" + #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; #line 560 "Python/executor_cases.c.h" STACK_SHRINK(2); @@ -564,12 +564,12 @@ case CALL_INTRINSIC_1: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 705 "Python/bytecodes.c" + #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 571 "Python/executor_cases.c.h" Py_DECREF(value); - #line 708 "Python/bytecodes.c" + #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 575 "Python/executor_cases.c.h" stack_pointer[-1] = res; @@ -580,13 +580,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 712 "Python/bytecodes.c" + #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 587 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 715 "Python/bytecodes.c" + #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 592 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -597,7 +597,7 @@ case GET_AITER: { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 820 "Python/bytecodes.c" + #line 819 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -612,14 +612,14 @@ type->tp_name); #line 614 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 833 "Python/bytecodes.c" + #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 621 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 838 "Python/bytecodes.c" + #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -640,7 +640,7 @@ case GET_ANEXT: { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 853 "Python/bytecodes.c" + #line 852 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -692,7 +692,7 @@ case GET_AWAITABLE: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 898 "Python/bytecodes.c" + #line 897 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -701,7 +701,7 @@ #line 703 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 905 "Python/bytecodes.c" + #line 904 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -725,7 +725,7 @@ case POP_EXCEPT: { PyObject *exc_value = stack_pointer[-1]; - #line 1035 "Python/bytecodes.c" + #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 732 "Python/executor_cases.c.h" @@ -735,7 +735,7 @@ case LOAD_ASSERTION_ERROR: { PyObject *value; - #line 1086 "Python/bytecodes.c" + #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 741 "Python/executor_cases.c.h" STACK_GROW(1); @@ -745,7 +745,7 @@ case LOAD_BUILD_CLASS: { PyObject *bc; - #line 1090 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -775,7 +775,7 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; - #line 1115 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -784,7 +784,7 @@ "no locals found when storing %R", name); #line 786 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1122 "Python/bytecodes.c" + #line 1121 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -793,7 +793,7 @@ err = PyObject_SetItem(ns, name, v); #line 795 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1129 "Python/bytecodes.c" + #line 1128 "Python/bytecodes.c" if (err) goto pop_1_error; #line 799 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -801,7 +801,7 @@ } case DELETE_NAME: { - #line 1133 "Python/bytecodes.c" + #line 1132 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -825,7 +825,7 @@ case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1176 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -842,7 +842,7 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1186 "Python/bytecodes.c" + #line 1185 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -860,7 +860,7 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1197 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -877,13 +877,13 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; - #line 1208 "Python/bytecodes.c" + #line 1207 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 885 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1212 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 889 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -892,12 +892,12 @@ case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; - #line 1243 "Python/bytecodes.c" + #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 899 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1246 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" if (err) goto pop_1_error; #line 903 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -906,12 +906,12 @@ case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; - #line 1250 "Python/bytecodes.c" + #line 1249 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 913 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1253 "Python/bytecodes.c" + #line 1252 "Python/bytecodes.c" if (err) goto pop_1_error; #line 917 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -919,7 +919,7 @@ } case DELETE_GLOBAL: { - #line 1257 "Python/bytecodes.c" + #line 1256 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -937,7 +937,7 @@ case _LOAD_LOCALS: { PyObject *locals; - #line 1271 "Python/bytecodes.c" + #line 1270 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -954,7 +954,7 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; - #line 1283 "Python/bytecodes.c" + #line 1282 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1017,7 +1017,7 @@ } case DELETE_DEREF: { - #line 1453 "Python/bytecodes.c" + #line 1452 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1035,7 +1035,7 @@ case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1466 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -1077,7 +1077,7 @@ case LOAD_DEREF: { PyObject *value; - #line 1503 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1093,7 +1093,7 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1513 "Python/bytecodes.c" + #line 1512 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -1104,7 +1104,7 @@ } case COPY_FREE_VARS: { - #line 1520 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1122,13 +1122,13 @@ case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1533 "Python/bytecodes.c" + #line 1532 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 1128 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1535 "Python/bytecodes.c" + #line 1534 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 1134 "Python/executor_cases.c.h" STACK_SHRINK(oparg); @@ -1140,7 +1140,7 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1539 "Python/bytecodes.c" + #line 1538 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 1147 "Python/executor_cases.c.h" @@ -1153,7 +1153,7 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1544 "Python/bytecodes.c" + #line 1543 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 1160 "Python/executor_cases.c.h" @@ -1166,7 +1166,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1549 "Python/bytecodes.c" + #line 1548 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1179,7 +1179,7 @@ } #line 1181 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1560 "Python/bytecodes.c" + #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -1192,11 +1192,11 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1567 "Python/bytecodes.c" + #line 1566 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 1198 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1569 "Python/bytecodes.c" + #line 1568 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 1202 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -1206,7 +1206,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1573 "Python/bytecodes.c" + #line 1572 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1231,7 +1231,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1590 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1243,7 +1243,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1598 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 1249 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); @@ -1253,7 +1253,7 @@ } case SETUP_ANNOTATIONS: { - #line 1602 "Python/bytecodes.c" + #line 1601 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1301,7 +1301,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1644 "Python/bytecodes.c" + #line 1643 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1316,7 +1316,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1654 "Python/bytecodes.c" + #line 1653 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 1322 "Python/executor_cases.c.h" STACK_SHRINK(oparg); @@ -1326,7 +1326,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1658 "Python/bytecodes.c" + #line 1657 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1336,7 +1336,7 @@ } #line 1338 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1666 "Python/bytecodes.c" + #line 1665 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1343 "Python/executor_cases.c.h" @@ -1347,14 +1347,14 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1672 "Python/bytecodes.c" + #line 1671 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 1356 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1677 "Python/bytecodes.c" + #line 1676 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1361 "Python/executor_cases.c.h" @@ -1366,7 +1366,7 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1683 "Python/bytecodes.c" + #line 1682 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -1383,7 +1383,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1766 "Python/bytecodes.c" + #line 1765 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1394,7 +1394,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1773 "Python/bytecodes.c" + #line 1772 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 1400 "Python/executor_cases.c.h" STACK_SHRINK(2); @@ -1410,7 +1410,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1777 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1444,7 +1444,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2115 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1466,7 +1466,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2130 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1492,7 +1492,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2149 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1515,12 +1515,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2164 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 1521 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2166 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1526 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -1532,12 +1532,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2170 "Python/bytecodes.c" + #line 2169 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 1538 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2172 "Python/bytecodes.c" + #line 2171 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 1544 "Python/executor_cases.c.h" @@ -1551,12 +1551,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2177 "Python/bytecodes.c" + #line 2176 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 1557 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2179 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1567,7 +1567,7 @@ #line 1568 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2187 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1586,19 +1586,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2198 "Python/bytecodes.c" + #line 2197 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 1593 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2201 "Python/bytecodes.c" + #line 2200 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 1600 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2206 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1604 "Python/executor_cases.c.h" stack_pointer[-1] = b; @@ -1608,7 +1608,7 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2305 "Python/bytecodes.c" + #line 2304 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -1625,7 +1625,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2313 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -1634,7 +1634,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2318 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1651,7 +1651,7 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2328 "Python/bytecodes.c" + #line 2327 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 1658 "Python/executor_cases.c.h" @@ -1663,7 +1663,7 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2333 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 1670 "Python/executor_cases.c.h" @@ -1676,7 +1676,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2338 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -1689,12 +1689,12 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2344 "Python/bytecodes.c" + #line 2343 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 1696 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2347 "Python/bytecodes.c" + #line 2346 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 1700 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1704,7 +1704,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2351 "Python/bytecodes.c" + #line 2350 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1729,7 +1729,7 @@ } #line 1731 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2374 "Python/bytecodes.c" + #line 2373 "Python/bytecodes.c" } #line 1735 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1741,7 +1741,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2606 "Python/bytecodes.c" + #line 2605 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -1771,7 +1771,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2645 "Python/bytecodes.c" + #line 2644 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -1790,7 +1790,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3014 "Python/bytecodes.c" + #line 3013 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1806,7 +1806,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3428 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1826,7 +1826,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3442 "Python/bytecodes.c" + #line 3441 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1862,13 +1862,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3492 "Python/bytecodes.c" + #line 3491 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 1868 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3494 "Python/bytecodes.c" + #line 3493 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 1874 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -1880,7 +1880,7 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3498 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -1895,7 +1895,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3507 "Python/bytecodes.c" + #line 3506 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1915,7 +1915,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3520 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -1929,7 +1929,7 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3527 "Python/bytecodes.c" + #line 3526 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 1936 "Python/executor_cases.c.h" @@ -1941,7 +1941,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3552 "Python/bytecodes.c" + #line 3551 "Python/bytecodes.c" assert(oparg >= 2); #line 1947 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 568d15ee7edf23..21cd2d0126ab30 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 137 "Python/bytecodes.c" + #line 136 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -25,7 +25,7 @@ } TARGET(INSTRUMENTED_RESUME) { - #line 151 "Python/bytecodes.c" + #line 150 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? @@ -57,7 +57,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 183 "Python/bytecodes.c" + #line 182 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -69,7 +69,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 189 "Python/bytecodes.c" + #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -81,7 +81,7 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 195 "Python/bytecodes.c" + #line 194 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; @@ -94,7 +94,7 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 201 "Python/bytecodes.c" + #line 200 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); @@ -110,7 +110,7 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 210 "Python/bytecodes.c" + #line 209 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); #line 117 "Python/generated_cases.c.h" @@ -121,7 +121,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 215 "Python/bytecodes.c" + #line 214 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 127 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -131,7 +131,7 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 223 "Python/bytecodes.c" + #line 222 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -145,7 +145,7 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 231 "Python/bytecodes.c" + #line 230 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); @@ -157,7 +157,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 238 "Python/bytecodes.c" + #line 237 "Python/bytecodes.c" #line 162 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -166,7 +166,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 242 "Python/bytecodes.c" + #line 241 "Python/bytecodes.c" res = NULL; #line 172 "Python/generated_cases.c.h" STACK_GROW(1); @@ -179,13 +179,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 238 "Python/bytecodes.c" + #line 237 "Python/bytecodes.c" #line 184 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 238 "Python/bytecodes.c" + #line 237 "Python/bytecodes.c" #line 190 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -196,7 +196,7 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 248 "Python/bytecodes.c" + #line 247 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -216,7 +216,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 261 "Python/bytecodes.c" + #line 260 "Python/bytecodes.c" Py_DECREF(receiver); #line 222 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -227,7 +227,7 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 265 "Python/bytecodes.c" + #line 264 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -245,11 +245,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 276 "Python/bytecodes.c" + #line 275 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 251 "Python/generated_cases.c.h" Py_DECREF(value); - #line 278 "Python/bytecodes.c" + #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 255 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -259,7 +259,7 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 282 "Python/bytecodes.c" + #line 281 "Python/bytecodes.c" assert(PyBool_Check(value)); res = Py_IsFalse(value) ? Py_True : Py_False; #line 266 "Python/generated_cases.c.h" @@ -272,7 +272,7 @@ static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value = stack_pointer[-1]; PyObject *res; - #line 297 "Python/bytecodes.c" + #line 296 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -286,7 +286,7 @@ int err = PyObject_IsTrue(value); #line 288 "Python/generated_cases.c.h" Py_DECREF(value); - #line 309 "Python/bytecodes.c" + #line 308 "Python/bytecodes.c" if (err < 0) goto pop_1_error; res = err ? Py_True : Py_False; #line 293 "Python/generated_cases.c.h" @@ -297,7 +297,7 @@ TARGET(TO_BOOL_BOOL) { PyObject *value = stack_pointer[-1]; - #line 314 "Python/bytecodes.c" + #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); #line 304 "Python/generated_cases.c.h" @@ -308,7 +308,7 @@ TARGET(TO_BOOL_INT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 319 "Python/bytecodes.c" + #line 318 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value)) { @@ -318,7 +318,7 @@ else { #line 320 "Python/generated_cases.c.h" Py_DECREF(value); - #line 327 "Python/bytecodes.c" + #line 326 "Python/bytecodes.c" res = Py_True; } #line 325 "Python/generated_cases.c.h" @@ -330,7 +330,7 @@ TARGET(TO_BOOL_LIST) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 332 "Python/bytecodes.c" + #line 331 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; @@ -344,7 +344,7 @@ TARGET(TO_BOOL_NONE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 339 "Python/bytecodes.c" + #line 338 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); @@ -358,7 +358,7 @@ TARGET(TO_BOOL_STR) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 346 "Python/bytecodes.c" + #line 345 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (value == &_Py_STR(empty)) { @@ -369,7 +369,7 @@ assert(Py_SIZE(value)); #line 371 "Python/generated_cases.c.h" Py_DECREF(value); - #line 355 "Python/bytecodes.c" + #line 354 "Python/bytecodes.c" res = Py_True; } #line 376 "Python/generated_cases.c.h" @@ -382,14 +382,14 @@ PyObject *value = stack_pointer[-1]; PyObject *res; uint32_t version = read_u32(&next_instr[1].cache); - #line 360 "Python/bytecodes.c" + #line 359 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); #line 391 "Python/generated_cases.c.h" Py_DECREF(value); - #line 365 "Python/bytecodes.c" + #line 364 "Python/bytecodes.c" res = Py_True; #line 395 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -400,11 +400,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 369 "Python/bytecodes.c" + #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 406 "Python/generated_cases.c.h" Py_DECREF(value); - #line 371 "Python/bytecodes.c" + #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 410 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -417,7 +417,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 424 "Python/generated_cases.c.h" @@ -428,7 +428,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 392 "Python/bytecodes.c" + #line 391 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -449,7 +449,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 456 "Python/generated_cases.c.h" @@ -460,7 +460,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 400 "Python/bytecodes.c" + #line 399 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -481,7 +481,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 387 "Python/bytecodes.c" + #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); #line 488 "Python/generated_cases.c.h" @@ -492,7 +492,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 408 "Python/bytecodes.c" + #line 407 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -513,7 +513,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 423 "Python/bytecodes.c" + #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 520 "Python/generated_cases.c.h" @@ -524,7 +524,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 428 "Python/bytecodes.c" + #line 427 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * @@ -545,7 +545,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 423 "Python/bytecodes.c" + #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 552 "Python/generated_cases.c.h" @@ -556,7 +556,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 436 "Python/bytecodes.c" + #line 435 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + @@ -577,7 +577,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 423 "Python/bytecodes.c" + #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); #line 584 "Python/generated_cases.c.h" @@ -588,7 +588,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 444 "Python/bytecodes.c" + #line 443 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - @@ -609,7 +609,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 459 "Python/bytecodes.c" + #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 616 "Python/generated_cases.c.h" @@ -620,7 +620,7 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 464 "Python/bytecodes.c" + #line 463 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); @@ -641,7 +641,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 459 "Python/bytecodes.c" + #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); #line 648 "Python/generated_cases.c.h" @@ -651,7 +651,7 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 481 "Python/bytecodes.c" + #line 480 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -687,7 +687,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 518 "Python/bytecodes.c" + #line 517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -702,7 +702,7 @@ #line 703 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 530 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 708 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -716,7 +716,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 534 "Python/bytecodes.c" + #line 533 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -740,7 +740,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 549 "Python/bytecodes.c" + #line 548 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -762,7 +762,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 564 "Python/bytecodes.c" + #line 563 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -787,7 +787,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 580 "Python/bytecodes.c" + #line 579 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -812,7 +812,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 596 "Python/bytecodes.c" + #line 595 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -823,7 +823,7 @@ #line 824 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 604 "Python/bytecodes.c" + #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -839,7 +839,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 611 "Python/bytecodes.c" + #line 610 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -868,7 +868,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 636 "Python/bytecodes.c" + #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 874 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -878,11 +878,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 640 "Python/bytecodes.c" + #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 884 "Python/generated_cases.c.h" Py_DECREF(v); - #line 642 "Python/bytecodes.c" + #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; #line 888 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -896,7 +896,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 652 "Python/bytecodes.c" + #line 651 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -915,7 +915,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 667 "Python/bytecodes.c" + #line 666 "Python/bytecodes.c" if (err) goto pop_3_error; #line 921 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -927,7 +927,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 671 "Python/bytecodes.c" + #line 670 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -954,7 +954,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 690 "Python/bytecodes.c" + #line 689 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); @@ -969,13 +969,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 698 "Python/bytecodes.c" + #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 976 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 701 "Python/bytecodes.c" + #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; #line 981 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -985,12 +985,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 705 "Python/bytecodes.c" + #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 992 "Python/generated_cases.c.h" Py_DECREF(value); - #line 708 "Python/bytecodes.c" + #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 996 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -1001,13 +1001,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 712 "Python/bytecodes.c" + #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 1008 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 715 "Python/bytecodes.c" + #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 1013 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1017,7 +1017,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 719 "Python/bytecodes.c" + #line 718 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -1040,7 +1040,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 739 "Python/bytecodes.c" + #line 738 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -1054,7 +1054,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 750 "Python/bytecodes.c" + #line 749 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1072,7 +1072,7 @@ TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 765 "Python/bytecodes.c" + #line 764 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -1093,7 +1093,7 @@ } TARGET(RETURN_CONST) { - #line 784 "Python/bytecodes.c" + #line 783 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1111,7 +1111,7 @@ } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 800 "Python/bytecodes.c" + #line 799 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1135,7 +1135,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 820 "Python/bytecodes.c" + #line 819 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1150,14 +1150,14 @@ type->tp_name); #line 1152 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 833 "Python/bytecodes.c" + #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 1159 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 838 "Python/bytecodes.c" + #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1178,7 +1178,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 853 "Python/bytecodes.c" + #line 852 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1230,7 +1230,7 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 898 "Python/bytecodes.c" + #line 897 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -1239,7 +1239,7 @@ #line 1241 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 905 "Python/bytecodes.c" + #line 904 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1267,7 +1267,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 929 "Python/bytecodes.c" + #line 928 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1323,7 +1323,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 978 "Python/bytecodes.c" + #line 977 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1344,7 +1344,7 @@ TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 996 "Python/bytecodes.c" + #line 995 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1367,7 +1367,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 1016 "Python/bytecodes.c" + #line 1015 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1389,7 +1389,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 1035 "Python/bytecodes.c" + #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1396 "Python/generated_cases.c.h" @@ -1400,7 +1400,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 1040 "Python/bytecodes.c" + #line 1039 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1424,13 +1424,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 1060 "Python/bytecodes.c" + #line 1059 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1431 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 1063 "Python/bytecodes.c" + #line 1062 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1448,7 +1448,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1072 "Python/bytecodes.c" + #line 1071 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1457,7 +1457,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1077 "Python/bytecodes.c" + #line 1076 "Python/bytecodes.c" none = Py_None; } else { @@ -1473,7 +1473,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1086 "Python/bytecodes.c" + #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1479 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1483,7 +1483,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1090 "Python/bytecodes.c" + #line 1089 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1513,7 +1513,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1115 "Python/bytecodes.c" + #line 1114 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1522,7 +1522,7 @@ "no locals found when storing %R", name); #line 1524 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1122 "Python/bytecodes.c" + #line 1121 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1531,7 +1531,7 @@ err = PyObject_SetItem(ns, name, v); #line 1533 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1129 "Python/bytecodes.c" + #line 1128 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1537 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1539,7 +1539,7 @@ } TARGET(DELETE_NAME) { - #line 1133 "Python/bytecodes.c" + #line 1132 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1564,7 +1564,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1159 "Python/bytecodes.c" + #line 1158 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1579,7 +1579,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1581 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1172 "Python/bytecodes.c" + #line 1171 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1585 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1591,7 +1591,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1176 "Python/bytecodes.c" + #line 1175 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1609,7 +1609,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1186 "Python/bytecodes.c" + #line 1185 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1628,7 +1628,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1197 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1646,13 +1646,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1208 "Python/bytecodes.c" + #line 1207 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1654 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1212 "Python/bytecodes.c" + #line 1211 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1658 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1665,7 +1665,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1223 "Python/bytecodes.c" + #line 1222 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1684,7 +1684,7 @@ #line 1685 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1239 "Python/bytecodes.c" + #line 1238 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1690 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1694,12 +1694,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1243 "Python/bytecodes.c" + #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1701 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1246 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1705 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1708,12 +1708,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1250 "Python/bytecodes.c" + #line 1249 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1715 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1253 "Python/bytecodes.c" + #line 1252 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1719 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1721,7 +1721,7 @@ } TARGET(DELETE_GLOBAL) { - #line 1257 "Python/bytecodes.c" + #line 1256 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1741,7 +1741,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1271 "Python/bytecodes.c" + #line 1270 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1761,7 +1761,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1271 "Python/bytecodes.c" + #line 1270 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1775,7 +1775,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1283 "Python/bytecodes.c" + #line 1282 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1845,7 +1845,7 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1283 "Python/bytecodes.c" + #line 1282 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyDict_CheckExact(mod_or_class_dict)) { v = PyDict_GetItemWithError(mod_or_class_dict, name); @@ -1914,7 +1914,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1352 "Python/bytecodes.c" + #line 1351 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1980,7 +1980,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1406 "Python/bytecodes.c" + #line 1405 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -2006,7 +2006,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1419 "Python/bytecodes.c" + #line 1418 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -2031,7 +2031,7 @@ } TARGET(DELETE_FAST) { - #line 1436 "Python/bytecodes.c" + #line 1435 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -2040,7 +2040,7 @@ } TARGET(MAKE_CELL) { - #line 1442 "Python/bytecodes.c" + #line 1441 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -2054,7 +2054,7 @@ } TARGET(DELETE_DEREF) { - #line 1453 "Python/bytecodes.c" + #line 1452 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -2072,7 +2072,7 @@ TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1466 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -2114,7 +2114,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1503 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2130,7 +2130,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1513 "Python/bytecodes.c" + #line 1512 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -2141,7 +2141,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1520 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2159,13 +2159,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1533 "Python/bytecodes.c" + #line 1532 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 2165 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1535 "Python/bytecodes.c" + #line 1534 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 2171 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2177,7 +2177,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1539 "Python/bytecodes.c" + #line 1538 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 2184 "Python/generated_cases.c.h" @@ -2190,7 +2190,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1544 "Python/bytecodes.c" + #line 1543 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 2197 "Python/generated_cases.c.h" @@ -2203,7 +2203,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1549 "Python/bytecodes.c" + #line 1548 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2216,7 +2216,7 @@ } #line 2218 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1560 "Python/bytecodes.c" + #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); @@ -2229,11 +2229,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1567 "Python/bytecodes.c" + #line 1566 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 2235 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1569 "Python/bytecodes.c" + #line 1568 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 2239 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2243,7 +2243,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1573 "Python/bytecodes.c" + #line 1572 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2268,7 +2268,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1590 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2280,7 +2280,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1598 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 2286 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -2290,7 +2290,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1602 "Python/bytecodes.c" + #line 1601 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2338,7 +2338,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1644 "Python/bytecodes.c" + #line 1643 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2353,7 +2353,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1654 "Python/bytecodes.c" + #line 1653 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 2359 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -2363,7 +2363,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1658 "Python/bytecodes.c" + #line 1657 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2373,7 +2373,7 @@ } #line 2375 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1666 "Python/bytecodes.c" + #line 1665 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2380 "Python/generated_cases.c.h" @@ -2384,14 +2384,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1672 "Python/bytecodes.c" + #line 1671 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2393 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1677 "Python/bytecodes.c" + #line 1676 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2398 "Python/generated_cases.c.h" @@ -2403,7 +2403,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1683 "Python/bytecodes.c" + #line 1682 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2415,7 +2415,7 @@ } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1691 "Python/bytecodes.c" + #line 1690 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -2432,7 +2432,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1705 "Python/bytecodes.c" + #line 1704 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2478,7 +2478,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1747 "Python/bytecodes.c" + #line 1746 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); @@ -2498,7 +2498,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1766 "Python/bytecodes.c" + #line 1765 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2509,7 +2509,7 @@ Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1773 "Python/bytecodes.c" + #line 1772 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; #line 2515 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -2526,7 +2526,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1777 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2563,7 +2563,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1816 "Python/bytecodes.c" + #line 1815 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2599,7 +2599,7 @@ */ #line 2601 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1850 "Python/bytecodes.c" + #line 1849 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2610,7 +2610,7 @@ res = PyObject_GetAttr(owner, name); #line 2612 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1859 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2617 "Python/generated_cases.c.h" @@ -2627,7 +2627,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1868 "Python/bytecodes.c" + #line 1867 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2655,7 +2655,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1884 "Python/bytecodes.c" + #line 1883 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2683,7 +2683,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1900 "Python/bytecodes.c" + #line 1899 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2725,7 +2725,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1930 "Python/bytecodes.c" + #line 1929 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2750,7 +2750,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1943 "Python/bytecodes.c" + #line 1942 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2776,7 +2776,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1958 "Python/bytecodes.c" + #line 1957 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2808,7 +2808,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1984 "Python/bytecodes.c" + #line 1983 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2842,7 +2842,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2012 "Python/bytecodes.c" + #line 2011 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2871,7 +2871,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 2032 "Python/bytecodes.c" + #line 2031 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2921,7 +2921,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2073 "Python/bytecodes.c" + #line 2072 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2943,7 +2943,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2092 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2959,7 +2959,7 @@ #line 2960 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2105 "Python/bytecodes.c" + #line 2104 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2978,7 +2978,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2115 "Python/bytecodes.c" + #line 2114 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -3001,7 +3001,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2130 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -3028,7 +3028,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2149 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -3052,12 +3052,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2164 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 3058 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2166 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3063 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3069,12 +3069,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2170 "Python/bytecodes.c" + #line 2169 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 3075 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2172 "Python/bytecodes.c" + #line 2171 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 3081 "Python/generated_cases.c.h" @@ -3088,12 +3088,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2177 "Python/bytecodes.c" + #line 2176 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 3094 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2179 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3104,7 +3104,7 @@ #line 3105 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2187 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3123,19 +3123,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2198 "Python/bytecodes.c" + #line 2197 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3130 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2201 "Python/bytecodes.c" + #line 2200 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3137 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2206 "Python/bytecodes.c" + #line 2205 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3141 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3146,13 +3146,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2210 "Python/bytecodes.c" + #line 2209 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3153 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2213 "Python/bytecodes.c" + #line 2212 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3158 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3163,7 +3163,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2217 "Python/bytecodes.c" + #line 2216 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3174,14 +3174,14 @@ } TARGET(JUMP_FORWARD) { - #line 2223 "Python/bytecodes.c" + #line 2222 "Python/bytecodes.c" JUMPBY(oparg); #line 3180 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2227 "Python/bytecodes.c" + #line 2226 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3205,7 +3205,7 @@ } TARGET(ENTER_EXECUTOR) { - #line 2258 "Python/bytecodes.c" + #line 2257 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); @@ -3220,7 +3220,7 @@ TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2270 "Python/bytecodes.c" + #line 2269 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); #line 3227 "Python/generated_cases.c.h" @@ -3230,7 +3230,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2275 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); #line 3237 "Python/generated_cases.c.h" @@ -3240,11 +3240,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2280 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3246 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2282 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" JUMPBY(oparg); } #line 3251 "Python/generated_cases.c.h" @@ -3254,14 +3254,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2287 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3263 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2292 "Python/bytecodes.c" + #line 2291 "Python/bytecodes.c" } #line 3267 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3269,7 +3269,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2296 "Python/bytecodes.c" + #line 2295 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3283,7 +3283,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2305 "Python/bytecodes.c" + #line 2304 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3300,7 +3300,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2313 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3309,7 +3309,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2318 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3326,7 +3326,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2328 "Python/bytecodes.c" + #line 2327 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3333 "Python/generated_cases.c.h" @@ -3338,7 +3338,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2333 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3345 "Python/generated_cases.c.h" @@ -3351,7 +3351,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2338 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -3364,12 +3364,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2344 "Python/bytecodes.c" + #line 2343 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3371 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2347 "Python/bytecodes.c" + #line 2346 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3375 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3379,7 +3379,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2351 "Python/bytecodes.c" + #line 2350 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3404,7 +3404,7 @@ } #line 3406 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2374 "Python/bytecodes.c" + #line 2373 "Python/bytecodes.c" } #line 3410 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3416,7 +3416,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2392 "Python/bytecodes.c" + #line 2391 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3456,7 +3456,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2426 "Python/bytecodes.c" + #line 2425 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3489,7 +3489,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2454 "Python/bytecodes.c" + #line 2453 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3520,7 +3520,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2477 "Python/bytecodes.c" + #line 2476 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3551,7 +3551,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2500 "Python/bytecodes.c" + #line 2499 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3579,7 +3579,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2521 "Python/bytecodes.c" + #line 2520 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3602,7 +3602,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2539 "Python/bytecodes.c" + #line 2538 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3627,7 +3627,7 @@ } #line 3629 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2562 "Python/bytecodes.c" + #line 2561 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3645,7 +3645,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2571 "Python/bytecodes.c" + #line 2570 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3673,7 +3673,7 @@ } #line 3675 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2597 "Python/bytecodes.c" + #line 2596 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3692,7 +3692,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2606 "Python/bytecodes.c" + #line 2605 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3722,7 +3722,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2645 "Python/bytecodes.c" + #line 2644 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3746,7 +3746,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2657 "Python/bytecodes.c" + #line 2656 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3777,7 +3777,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2676 "Python/bytecodes.c" + #line 2675 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3801,7 +3801,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2688 "Python/bytecodes.c" + #line 2687 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3824,7 +3824,7 @@ } TARGET(KW_NAMES) { - #line 2704 "Python/bytecodes.c" + #line 2703 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); @@ -3833,7 +3833,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2710 "Python/bytecodes.c" + #line 2709 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3856,7 +3856,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2756 "Python/bytecodes.c" + #line 2755 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3950,7 +3950,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2844 "Python/bytecodes.c" + #line 2843 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3969,7 +3969,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2856 "Python/bytecodes.c" + #line 2855 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4003,7 +4003,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2884 "Python/bytecodes.c" + #line 2883 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4047,7 +4047,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2922 "Python/bytecodes.c" + #line 2921 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4070,7 +4070,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2934 "Python/bytecodes.c" + #line 2933 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4095,7 +4095,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2948 "Python/bytecodes.c" + #line 2947 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4119,7 +4119,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2962 "Python/bytecodes.c" + #line 2961 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4174,7 +4174,7 @@ TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3014 "Python/bytecodes.c" + #line 3013 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4192,7 +4192,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3024 "Python/bytecodes.c" + #line 3023 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4228,7 +4228,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3049 "Python/bytecodes.c" + #line 3048 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4270,7 +4270,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3080 "Python/bytecodes.c" + #line 3079 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4316,7 +4316,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3115 "Python/bytecodes.c" + #line 3114 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4362,7 +4362,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3150 "Python/bytecodes.c" + #line 3149 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4400,7 +4400,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3177 "Python/bytecodes.c" + #line 3176 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4439,7 +4439,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3207 "Python/bytecodes.c" + #line 3206 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4464,7 +4464,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3227 "Python/bytecodes.c" + #line 3226 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4508,7 +4508,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3261 "Python/bytecodes.c" + #line 3260 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4550,7 +4550,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3293 "Python/bytecodes.c" + #line 3292 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4592,7 +4592,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3325 "Python/bytecodes.c" + #line 3324 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4630,7 +4630,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3356 "Python/bytecodes.c" + #line 3355 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4636 "Python/generated_cases.c.h" } @@ -4641,7 +4641,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3360 "Python/bytecodes.c" + #line 3359 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4707,7 +4707,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3422 "Python/bytecodes.c" + #line 3421 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4714 "Python/generated_cases.c.h" @@ -4721,7 +4721,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3428 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4741,7 +4741,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3442 "Python/bytecodes.c" + #line 3441 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4773,7 +4773,7 @@ } TARGET(RETURN_GENERATOR) { - #line 3469 "Python/bytecodes.c" + #line 3468 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4802,13 +4802,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3492 "Python/bytecodes.c" + #line 3491 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4808 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3494 "Python/bytecodes.c" + #line 3493 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4814 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4820,7 +4820,7 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3498 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -4835,7 +4835,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3507 "Python/bytecodes.c" + #line 3506 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4855,7 +4855,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3520 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -4869,7 +4869,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3527 "Python/bytecodes.c" + #line 3526 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4876 "Python/generated_cases.c.h" @@ -4884,7 +4884,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3532 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4902,7 +4902,7 @@ #line 4903 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3547 "Python/bytecodes.c" + #line 3546 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4908 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4914,7 +4914,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3552 "Python/bytecodes.c" + #line 3551 "Python/bytecodes.c" assert(oparg >= 2); #line 4920 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4923,7 +4923,7 @@ } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3556 "Python/bytecodes.c" + #line 3555 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4939,14 +4939,14 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3570 "Python/bytecodes.c" + #line 3569 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); #line 4945 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3574 "Python/bytecodes.c" + #line 3573 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); #line 4952 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); @@ -4954,7 +4954,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3579 "Python/bytecodes.c" + #line 3578 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; @@ -4965,7 +4965,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3587 "Python/bytecodes.c" + #line 3586 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; @@ -4976,7 +4976,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3595 "Python/bytecodes.c" + #line 3594 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4993,7 +4993,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3609 "Python/bytecodes.c" + #line 3608 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5010,7 +5010,7 @@ } TARGET(EXTENDED_ARG) { - #line 3623 "Python/bytecodes.c" + #line 3622 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; @@ -5020,14 +5020,14 @@ } TARGET(CACHE) { - #line 3631 "Python/bytecodes.c" + #line 3630 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); #line 5027 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3636 "Python/bytecodes.c" + #line 3635 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); #line 5034 "Python/generated_cases.c.h" diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 26e474a3efefd1..60bf66c8a6bf89 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -834,11 +834,8 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) _PyErr_WriteUnraisableMsg("in audit hook", NULL); } if (hook) { - PyObject* stack[3]; - stack[0] = typ; - stack[1] = exc; - stack[2] = tb; - PyObject *result = _PyObject_FastCall(hook, stack, 3); + PyObject* args[3] = {typ, exc, tb}; + PyObject *result = PyObject_Vectorcall(hook, args, 3, NULL); if (result == NULL) { handle_system_exit(); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 0cd8974d197133..723fcdb174ab30 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -268,7 +268,7 @@ sys_audit_tstate(PyThreadState *ts, const char *event, PyThreadState_LeaveTracing(ts); } PyObject* args[2] = {eventName, eventArgs}; - o = _PyObject_FastCallTstate(ts, hook, args, 2); + o = _PyObject_VectorcallTstate(ts, hook, args, 2, NULL); if (canTrace) { PyThreadState_EnterTracing(ts); } From cd580910e10dcfffa364d08ee5a6f0257d031baf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 03:07:59 +0200 Subject: [PATCH 190/446] gh-106023: Remove _PY_FASTCALL_SMALL_STACK constant (#106258) Remove _PY_FASTCALL_SMALL_STACK constant from the C API: move it to the internal C API (pycore_call.h). --- Include/cpython/abstract.h | 13 ------------- Include/internal/pycore_call.h | 12 ++++++++++++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 2e76ff49a81dd3..d563d1b29ac3b3 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -2,19 +2,6 @@ # error "this header file must not be included directly" #endif -/* === Object Protocol ================================================== */ - -/* Suggested size (number of positional arguments) for arrays of PyObject* - allocated on a C stack to avoid allocating memory on the heap memory. Such - array is used to pass positional arguments to call functions of the - PyObject_Vectorcall() family. - - The size is chosen to not abuse the C stack and so limit the risk of stack - overflow. The size is also chosen to allow using the small stack for most - function calls of the Python standard library. On 64-bit CPU, it allocates - 40 bytes on the stack. */ -#define _PY_FASTCALL_SMALL_STACK 5 - /* === Vectorcall protocol (PEP 590) ============================= */ // PyVectorcall_NARGS() is exported as a function for the stable ABI. diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 3caf504a96aa3a..66434cc048cc92 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -10,6 +10,18 @@ extern "C" { #include "pycore_pystate.h" // _PyThreadState_GET() +/* Suggested size (number of positional arguments) for arrays of PyObject* + allocated on a C stack to avoid allocating memory on the heap memory. Such + array is used to pass positional arguments to call functions of the + PyObject_Vectorcall() family. + + The size is chosen to not abuse the C stack and so limit the risk of stack + overflow. The size is also chosen to allow using the small stack for most + function calls of the Python standard library. On 64-bit CPU, it allocates + 40 bytes on the stack. */ +#define _PY_FASTCALL_SMALL_STACK 5 + + // Export for shared stdlib extensions like the math extension, // function used via inlined _PyObject_VectorcallTstate() function. PyAPI_FUNC(PyObject*) _Py_CheckFunctionResult( From 77ddc9a7b1b28c8b8aee6cc97e483185a56819a6 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 30 Jun 2023 13:00:22 +0900 Subject: [PATCH 191/446] fix typos (#106247) Most typos are in comments, but two typos are in docstring. --- Objects/bytearrayobject.c | 4 ++-- Objects/bytesobject.c | 4 ++-- Objects/clinic/bytearrayobject.c.h | 4 ++-- Objects/clinic/bytesobject.c.h | 4 ++-- Objects/exceptions.c | 2 +- Objects/object_layout.md | 2 +- Python/pytime.c | 2 +- Python/sysmodule.c | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index c36db59baaa10d..944ec65b64f6a2 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1377,7 +1377,7 @@ bytearray.maketrans to: Py_buffer / -Return a translation table useable for the bytes or bytearray translate method. +Return a translation table usable for the bytes or bytearray translate method. The returned table will be one where each byte in frm is mapped to the byte at the same position in to. @@ -1387,7 +1387,7 @@ The bytes objects frm and to must be of the same length. static PyObject * bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to) -/*[clinic end generated code: output=1df267d99f56b15e input=5925a81d2fbbf151]*/ +/*[clinic end generated code: output=1df267d99f56b15e input=b10de38c85950a63]*/ { return _Py_bytes_maketrans(frm, to); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 1b67e02025c424..bf54ec1d51d209 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2154,7 +2154,7 @@ bytes.maketrans to: Py_buffer / -Return a translation table useable for the bytes or bytearray translate method. +Return a translation table usable for the bytes or bytearray translate method. The returned table will be one where each byte in frm is mapped to the byte at the same position in to. @@ -2164,7 +2164,7 @@ The bytes objects frm and to must be of the same length. static PyObject * bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to) -/*[clinic end generated code: output=a36f6399d4b77f6f input=de7a8fc5632bb8f1]*/ +/*[clinic end generated code: output=a36f6399d4b77f6f input=a3bd00d430a0979f]*/ { return _Py_bytes_maketrans(frm, to); } diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index b847597c64b3f1..33caca28224565 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -289,7 +289,7 @@ PyDoc_STRVAR(bytearray_maketrans__doc__, "maketrans(frm, to, /)\n" "--\n" "\n" -"Return a translation table useable for the bytes or bytearray translate method.\n" +"Return a translation table usable for the bytes or bytearray translate method.\n" "\n" "The returned table will be one where each byte in frm is mapped to the byte at\n" "the same position in to.\n" @@ -1284,4 +1284,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl(self); } -/*[clinic end generated code: output=99fb3e3b9c1f4b15 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0817195f176cd8e3 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h index 4b4a4b39a1fa96..1ec0c95485a209 100644 --- a/Objects/clinic/bytesobject.c.h +++ b/Objects/clinic/bytesobject.c.h @@ -476,7 +476,7 @@ PyDoc_STRVAR(bytes_maketrans__doc__, "maketrans(frm, to, /)\n" "--\n" "\n" -"Return a translation table useable for the bytes or bytearray translate method.\n" +"Return a translation table usable for the bytes or bytearray translate method.\n" "\n" "The returned table will be one where each byte in frm is mapped to the byte at\n" "the same position in to.\n" @@ -1060,4 +1060,4 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=7b6e4e8b5bc4eb57 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bc4801bf1fa628f4 input=a9049054013a1b77]*/ diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 015dd27ec33308..2bfa07ea3121f4 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1464,7 +1464,7 @@ PyUnstable_Exc_PrepReraiseStar(PyObject *orig, PyObject *excs) } /* Make sure that orig has something as traceback, in the interpreter - * it always does becuase it's a raised exception. + * it always does because it's a raised exception. */ PyObject *tb = PyException_GetTraceback(orig); diff --git a/Objects/object_layout.md b/Objects/object_layout.md index 9380b57938c8e3..4430790f4f0f36 100644 --- a/Objects/object_layout.md +++ b/Objects/object_layout.md @@ -45,7 +45,7 @@ pointers are combined into a single tagged pointer: If the object has no physical dictionary, then the ``dict_or_values`` has its low bit set to one, and points to the values array. -If the object has a physical dictioanry, then the ``dict_or_values`` +If the object has a physical dictionary, then the ``dict_or_values`` has its low bit set to zero, and points to the dictionary. The untagged form is chosen for the dictionary pointer, rather than diff --git a/Python/pytime.c b/Python/pytime.c index acd1842056af43..d36d4417dabb22 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -969,7 +969,7 @@ py_get_system_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) } #if defined(HAVE_CLOCK_GETTIME_RUNTIME) && defined(HAVE_CLOCK_GETTIME) - } /* end of availibity block */ + } /* end of availability block */ #endif #endif /* !HAVE_CLOCK_GETTIME */ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 723fcdb174ab30..681024064ad40c 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -425,7 +425,7 @@ PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData) e->userData = userData; if (runtime->audit_hooks.mutex == NULL) { - /* The runtime must not be initailized yet. */ + /* The runtime must not be initialized yet. */ add_audit_hook_entry_unlocked(runtime, e); } else { From f1034ba7f67400e7ed7e299dc8b22521c4e43246 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 30 Jun 2023 13:02:03 +0900 Subject: [PATCH 192/446] gh-106182: sys: Intern getfilesystemencoding() and getfilesystemencodeerrors() (#106183) sys: Intern getfilesystemencoding() and getfilesystemencodeerrors() --- ...-06-28-15-19-59.gh-issue-106182.cDSFi0.rst | 2 ++ Python/sysmodule.c | 30 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-28-15-19-59.gh-issue-106182.cDSFi0.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-28-15-19-59.gh-issue-106182.cDSFi0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-28-15-19-59.gh-issue-106182.cDSFi0.rst new file mode 100644 index 00000000000000..ca2116b00a6659 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-28-15-19-59.gh-issue-106182.cDSFi0.rst @@ -0,0 +1,2 @@ +:func:`sys.getfilesystemencoding` and :mod:`sys.getfilesystemencodeerrors` +now return interned Unicode object. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 681024064ad40c..8e3fbe3314a951 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -863,6 +863,13 @@ sys_exit_impl(PyObject *module, PyObject *status) } +static PyObject * +get_utf8_unicode(void) +{ + _Py_DECLARE_STR(utf_8, "utf-8"); + PyObject *ret = &_Py_STR(utf_8); + return Py_NewRef(ret); +} /*[clinic input] sys.getdefaultencoding @@ -874,9 +881,7 @@ static PyObject * sys_getdefaultencoding_impl(PyObject *module) /*[clinic end generated code: output=256d19dfcc0711e6 input=d416856ddbef6909]*/ { - _Py_DECLARE_STR(utf_8, "utf-8"); - PyObject *ret = &_Py_STR(utf_8); - return Py_NewRef(ret); + return get_utf8_unicode(); } /*[clinic input] @@ -891,7 +896,17 @@ sys_getfilesystemencoding_impl(PyObject *module) { PyInterpreterState *interp = _PyInterpreterState_GET(); const PyConfig *config = _PyInterpreterState_GetConfig(interp); - return PyUnicode_FromWideChar(config->filesystem_encoding, -1); + + if (wcscmp(config->filesystem_encoding, L"utf-8") == 0) { + return get_utf8_unicode(); + } + + PyObject *u = PyUnicode_FromWideChar(config->filesystem_encoding, -1); + if (u == NULL) { + return NULL; + } + _PyUnicode_InternInPlace(interp, &u); + return u; } /*[clinic input] @@ -906,7 +921,12 @@ sys_getfilesystemencodeerrors_impl(PyObject *module) { PyInterpreterState *interp = _PyInterpreterState_GET(); const PyConfig *config = _PyInterpreterState_GetConfig(interp); - return PyUnicode_FromWideChar(config->filesystem_errors, -1); + PyObject *u = PyUnicode_FromWideChar(config->filesystem_errors, -1); + if (u == NULL) { + return NULL; + } + _PyUnicode_InternInPlace(interp, &u); + return u; } /*[clinic input] From e17420db5d0452a9c56c8cb324d37fc2c04309c0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 09:53:42 +0200 Subject: [PATCH 193/446] gh-106023: Rename _PyObject_FastCallDictTstate() (#106264) Rename _PyObject_FastCallDictTstate() to _PyObject_VectorcallDictTstate(). --- Include/internal/pycore_call.h | 2 +- Objects/call.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 66434cc048cc92..6058335cd4051a 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -49,7 +49,7 @@ extern PyObject* _PyObject_Call_Prepend( PyObject *args, PyObject *kwargs); -extern PyObject* _PyObject_FastCallDictTstate( +extern PyObject* _PyObject_VectorcallDictTstate( PyThreadState *tstate, PyObject *callable, PyObject *const *args, diff --git a/Objects/call.c b/Objects/call.c index fc8a6f9e0a0228..e745fc41feaac8 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -106,9 +106,9 @@ PyObject_CallNoArgs(PyObject *func) PyObject * -_PyObject_FastCallDictTstate(PyThreadState *tstate, PyObject *callable, - PyObject *const *args, size_t nargsf, - PyObject *kwargs) +_PyObject_VectorcallDictTstate(PyThreadState *tstate, PyObject *callable, + PyObject *const *args, size_t nargsf, + PyObject *kwargs) { assert(callable != NULL); @@ -154,7 +154,7 @@ PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwargs) { PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_FastCallDictTstate(tstate, callable, args, nargsf, kwargs); + return _PyObject_VectorcallDictTstate(tstate, callable, args, nargsf, kwargs); } static void @@ -453,7 +453,8 @@ PyEval_CallObjectWithKeywords(PyObject *callable, } if (args == NULL) { - return _PyObject_FastCallDictTstate(tstate, callable, NULL, 0, kwargs); + return _PyObject_VectorcallDictTstate(tstate, callable, + NULL, 0, kwargs); } else { return _PyObject_Call(tstate, callable, args, kwargs); @@ -506,9 +507,9 @@ _PyObject_Call_Prepend(PyThreadState *tstate, PyObject *callable, _PyTuple_ITEMS(args), argcount * sizeof(PyObject *)); - PyObject *result = _PyObject_FastCallDictTstate(tstate, callable, - stack, argcount + 1, - kwargs); + PyObject *result = _PyObject_VectorcallDictTstate(tstate, callable, + stack, argcount + 1, + kwargs); if (stack != small_stack) { PyMem_Free(stack); } From 0b51463862798d3124f542a076e02ea3759551a4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 11:34:01 +0200 Subject: [PATCH 194/446] Remove private _PyCodec_Lookup() function (#106269) Remove the following private functions of the C API: * _PyCodecInfo_GetIncrementalDecoder() * _PyCodecInfo_GetIncrementalEncoder() * _PyCodec_DecodeText() * _PyCodec_EncodeText() * _PyCodec_Forget() * _PyCodec_Lookup() * _PyCodec_LookupTextEncoding() Move these functions to a new pycore_codecs.h internal header file. These functions are no longer exported. --- Include/codecs.h | 120 ++++++----------------------- Include/internal/pycore_codecs.h | 53 +++++++++++++ Makefile.pre.in | 1 + Modules/_codecsmodule.c | 1 + Modules/_io/textio.c | 1 + Objects/unicodeobject.c | 3 +- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/pylifecycle.c | 1 + 9 files changed, 87 insertions(+), 97 deletions(-) create mode 100644 Include/internal/pycore_codecs.h diff --git a/Include/codecs.h b/Include/codecs.h index 37ecfb4ab757b4..512a3c723eca18 100644 --- a/Include/codecs.h +++ b/Include/codecs.h @@ -35,34 +35,6 @@ PyAPI_FUNC(int) PyCodec_Unregister( PyObject *search_function ); -/* Codec registry lookup API. - - Looks up the given encoding and returns a CodecInfo object with - function attributes which implement the different aspects of - processing the encoding. - - The encoding string is looked up converted to all lower-case - characters. This makes encodings looked up through this mechanism - effectively case-insensitive. - - If no codec is found, a KeyError is set and NULL returned. - - As side effect, this tries to load the encodings package, if not - yet done. This is part of the lazy load strategy for the encodings - package. - - */ - -#ifndef Py_LIMITED_API -PyAPI_FUNC(PyObject *) _PyCodec_Lookup( - const char *encoding - ); - -PyAPI_FUNC(int) _PyCodec_Forget( - const char *encoding - ); -#endif - /* Codec registry encoding check API. Returns 1/0 depending on whether there is a registered codec for @@ -106,102 +78,58 @@ PyAPI_FUNC(PyObject *) PyCodec_Decode( const char *errors ); -#ifndef Py_LIMITED_API -/* Text codec specific encoding and decoding API. - - Checks the encoding against a list of codecs which do not - implement a str<->bytes encoding before attempting the - operation. +// --- Codec Lookup APIs -------------------------------------------------- - Please note that these APIs are internal and should not - be used in Python C extensions. - - XXX (ncoghlan): should we make these, or something like them, public - in Python 3.5+? +/* Codec registry lookup API. - */ -PyAPI_FUNC(PyObject *) _PyCodec_LookupTextEncoding( - const char *encoding, - const char *alternate_command - ); + Looks up the given encoding and returns a CodecInfo object with + function attributes which implement the different aspects of + processing the encoding. -PyAPI_FUNC(PyObject *) _PyCodec_EncodeText( - PyObject *object, - const char *encoding, - const char *errors - ); + The encoding string is looked up converted to all lower-case + characters. This makes encodings looked up through this mechanism + effectively case-insensitive. -PyAPI_FUNC(PyObject *) _PyCodec_DecodeText( - PyObject *object, - const char *encoding, - const char *errors - ); + If no codec is found, a KeyError is set and NULL returned. -/* These two aren't actually text encoding specific, but _io.TextIOWrapper - * is the only current API consumer. + As side effect, this tries to load the encodings package, if not + yet done. This is part of the lazy load strategy for the encodings + package. */ -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalDecoder( - PyObject *codec_info, - const char *errors - ); - -PyAPI_FUNC(PyObject *) _PyCodecInfo_GetIncrementalEncoder( - PyObject *codec_info, - const char *errors - ); -#endif - - - -/* --- Codec Lookup APIs -------------------------------------------------- - - All APIs return a codec object with incremented refcount and are - based on _PyCodec_Lookup(). The same comments w/r to the encoding - name also apply to these APIs. - -*/ /* Get an encoder function for the given encoding. */ -PyAPI_FUNC(PyObject *) PyCodec_Encoder( - const char *encoding - ); +PyAPI_FUNC(PyObject *) PyCodec_Encoder(const char *encoding); /* Get a decoder function for the given encoding. */ -PyAPI_FUNC(PyObject *) PyCodec_Decoder( - const char *encoding - ); +PyAPI_FUNC(PyObject *) PyCodec_Decoder(const char *encoding); /* Get an IncrementalEncoder object for the given encoding. */ PyAPI_FUNC(PyObject *) PyCodec_IncrementalEncoder( - const char *encoding, - const char *errors - ); + const char *encoding, + const char *errors); /* Get an IncrementalDecoder object function for the given encoding. */ PyAPI_FUNC(PyObject *) PyCodec_IncrementalDecoder( - const char *encoding, - const char *errors - ); + const char *encoding, + const char *errors); /* Get a StreamReader factory function for the given encoding. */ PyAPI_FUNC(PyObject *) PyCodec_StreamReader( - const char *encoding, - PyObject *stream, - const char *errors - ); + const char *encoding, + PyObject *stream, + const char *errors); /* Get a StreamWriter factory function for the given encoding. */ PyAPI_FUNC(PyObject *) PyCodec_StreamWriter( - const char *encoding, - PyObject *stream, - const char *errors - ); + const char *encoding, + PyObject *stream, + const char *errors); /* Unicode encoding error handling callback registry API */ diff --git a/Include/internal/pycore_codecs.h b/Include/internal/pycore_codecs.h new file mode 100644 index 00000000000000..2f8d9d510019ba --- /dev/null +++ b/Include/internal/pycore_codecs.h @@ -0,0 +1,53 @@ +#ifndef Py_INTERNAL_CODECS_H +#define Py_INTERNAL_CODECS_H +#ifdef __cplusplus +extern "C" { +#endif + +extern PyObject* _PyCodec_Lookup(const char *encoding); + +extern int _PyCodec_Forget(const char *encoding); + +/* Text codec specific encoding and decoding API. + + Checks the encoding against a list of codecs which do not + implement a str<->bytes encoding before attempting the + operation. + + Please note that these APIs are internal and should not + be used in Python C extensions. + + XXX (ncoghlan): should we make these, or something like them, public + in Python 3.5+? + + */ +extern PyObject* _PyCodec_LookupTextEncoding( + const char *encoding, + const char *alternate_command); + +extern PyObject* _PyCodec_EncodeText( + PyObject *object, + const char *encoding, + const char *errors); + +extern PyObject* _PyCodec_DecodeText( + PyObject *object, + const char *encoding, + const char *errors); + +/* These two aren't actually text encoding specific, but _io.TextIOWrapper + * is the only current API consumer. + */ +extern PyObject* _PyCodecInfo_GetIncrementalDecoder( + PyObject *codec_info, + const char *errors); + +extern PyObject* _PyCodecInfo_GetIncrementalEncoder( + PyObject *codec_info, + const char *errors); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_CODECS_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 98b58cf1299f16..cd66c475665b2e 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1732,6 +1732,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_ceval.h \ $(srcdir)/Include/internal/pycore_ceval_state.h \ $(srcdir)/Include/internal/pycore_code.h \ + $(srcdir)/Include/internal/pycore_codecs.h \ $(srcdir)/Include/internal/pycore_compile.h \ $(srcdir)/Include/internal/pycore_condvar.h \ $(srcdir)/Include/internal/pycore_context.h \ diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index 777c753bd7c2a9..4dfd134f1cb11e 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -32,6 +32,7 @@ Copyright (c) Corporation for National Research Initiatives. #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_codecs.h" // _PyCodec_Lookup() #ifdef MS_WINDOWS #include diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index e6b1306c2f3f0b..c8e6792657cd58 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -9,6 +9,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() +#include "pycore_codecs.h" // _PyCodecInfo_GetIncrementalDecoder() #include "pycore_interp.h" // PyInterpreterState.fs_codec #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_fileutils.h" // _Py_GetLocaleEncoding() diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 38b72de88f3c0b..4434bf19d43b70 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -42,8 +42,9 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_atomic_funcs.h" // _Py_atomic_size_get() -#include "pycore_bytesobject.h" // _PyBytes_Repeat() #include "pycore_bytes_methods.h" // _Py_bytes_lower() +#include "pycore_bytesobject.h" // _PyBytes_Repeat() +#include "pycore_codecs.h" // _PyCodec_Lookup() #include "pycore_format.h" // F_LJUST #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // PyInterpreterState.fs_codec diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index a68452a916aa3c..4ccd2b5edd3f6e 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -209,6 +209,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index bf9b42f4d790e3..99f924856a354d 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -537,6 +537,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1df35ef4278677..cf8b4379c1467f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -4,6 +4,7 @@ #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_ceval.h" // _PyEval_FiniGIL() +#include "pycore_codecs.h" // _PyCodec_Lookup() #include "pycore_context.h" // _PyContext_Init() #include "pycore_dict.h" // _PyDict_Fini() #include "pycore_exceptions.h" // _PyExc_InitTypes() From 2efdd2a14e5036ba88f95f68e1f006d2ef08249e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 11:46:43 +0200 Subject: [PATCH 195/446] gh-106023: Remove _PyObject_FastCall() function (#106265) --- Doc/whatsnew/3.13.rst | 5 +++++ Include/cpython/abstract.h | 6 ------ Lib/test/test_call.py | 17 ++--------------- Lib/test/test_gdb.py | 8 ++++---- ...3-06-30-09-33-25.gh-issue-106023.YvYiE4.rst | 2 ++ Modules/_testcapi/vectorcall.c | 18 ------------------ Objects/call.c | 8 -------- 7 files changed, 13 insertions(+), 51 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-30-09-33-25.gh-issue-106023.YvYiE4.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index c0e9e924c8e82f..9696dd4ff0b700 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -597,3 +597,8 @@ Removed Just remove the underscore prefix to update your code. (Contributed by Victor Stinner in :gh:`106084`.) + +* Remove private ``_PyObject_FastCall()`` function: + use ``PyObject_Vectorcall()`` which is available since Python 3.8 + (:pep:`590`). + (Contributed by Victor Stinner in :gh:`106023`.) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index d563d1b29ac3b3..dd924dfd3d8fcc 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -24,12 +24,6 @@ PyAPI_FUNC(PyObject *) PyObject_VectorcallDict( size_t nargsf, PyObject *kwargs); -// Same as PyObject_Vectorcall(), except without keyword arguments -PyAPI_FUNC(PyObject *) _PyObject_FastCall( - PyObject *func, - PyObject *const *args, - Py_ssize_t nargs); - PyAPI_FUNC(PyObject *) PyObject_CallOneArg(PyObject *func, PyObject *arg); static inline PyObject * diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 5410131a7dfd89..09a531f8cc627b 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -519,19 +519,6 @@ def check_result(self, result, expected): expected = (*expected[:-1], result[-1]) self.assertEqual(result, expected) - def test_fastcall(self): - # Test _PyObject_FastCall() - - for func, args, expected in self.CALLS_POSARGS: - with self.subTest(func=func, args=args): - result = _testcapi.pyobject_fastcall(func, args) - self.check_result(result, expected) - - if not args: - # args=NULL, nargs=0 - result = _testcapi.pyobject_fastcall(func, None) - self.check_result(result, expected) - def test_vectorcall_dict(self): # Test PyObject_VectorcallDict() @@ -945,11 +932,11 @@ def py_recurse(n, m): def c_recurse(n): if n: - _testcapi.pyobject_fastcall(c_recurse, (n-1,)) + _testcapi.pyobject_vectorcall(c_recurse, (n-1,), ()) def c_py_recurse(m): if m: - _testcapi.pyobject_fastcall(py_recurse, (1000, m)) + _testcapi.pyobject_vectorcall(py_recurse, (1000, m), ()) depth = sys.getrecursionlimit() sys.setrecursionlimit(100_000) diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 311a864a52387d..85009089f21d2f 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -729,13 +729,13 @@ def test_two_abs_args(self): SAMPLE_WITH_C_CALL = """ -from _testcapi import pyobject_fastcall +from _testcapi import pyobject_vectorcall def foo(a, b, c): bar(a, b, c) def bar(a, b, c): - pyobject_fastcall(baz, (a, b, c)) + pyobject_vectorcall(baz, (a, b, c), None) def baz(*args): id(42) @@ -756,7 +756,7 @@ def test_pyup_command(self): self.assertMultilineMatches(bt, r'''^.* #[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) -#[0-9]+ +#[0-9]+ $''') @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") @@ -785,7 +785,7 @@ def test_up_then_down(self): self.assertMultilineMatches(bt, r'''^.* #[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) -#[0-9]+ +#[0-9]+ #[0-9]+ Frame 0x-?[0-9a-f]+, for file , line 12, in baz \(args=\(1, 2, 3\)\) $''') diff --git a/Misc/NEWS.d/next/C API/2023-06-30-09-33-25.gh-issue-106023.YvYiE4.rst b/Misc/NEWS.d/next/C API/2023-06-30-09-33-25.gh-issue-106023.YvYiE4.rst new file mode 100644 index 00000000000000..3130febf61120b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-30-09-33-25.gh-issue-106023.YvYiE4.rst @@ -0,0 +1,2 @@ +Remove private ``_PyObject_FastCall()`` function: use ``PyObject_Vectorcall()`` +which is available since Python 3.8 (:pep:`590`). Patch by Victor Stinner. diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index dcbc973c9fb991..4935fd1b6a7ba3 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -26,23 +26,6 @@ fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs) } -static PyObject * -test_pyobject_fastcall(PyObject *self, PyObject *args) -{ - PyObject *func, *func_args; - PyObject **stack; - Py_ssize_t nargs; - - if (!PyArg_ParseTuple(args, "OO", &func, &func_args)) { - return NULL; - } - - if (fastcall_args(func_args, &stack, &nargs) < 0) { - return NULL; - } - return _PyObject_FastCall(func, stack, nargs); -} - static PyObject * test_pyobject_fastcalldict(PyObject *self, PyObject *args) { @@ -259,7 +242,6 @@ _testcapi_has_vectorcall_flag_impl(PyObject *module, PyTypeObject *type) } static PyMethodDef TestMethods[] = { - {"pyobject_fastcall", test_pyobject_fastcall, METH_VARARGS}, {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS}, {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS}, {"function_setvectorcall", function_setvectorcall, METH_O}, diff --git a/Objects/call.c b/Objects/call.c index e745fc41feaac8..16c41ffe1d09b5 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -327,14 +327,6 @@ PyObject_Vectorcall(PyObject *callable, PyObject *const *args, } -PyObject * -_PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return _PyObject_FastCallTstate(tstate, func, args, nargs); -} - - PyObject * _PyObject_Call(PyThreadState *tstate, PyObject *callable, PyObject *args, PyObject *kwargs) From f3cf2ddd8ddc7dfa6b06e6da640391a1bcd62b8a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 11:57:06 +0200 Subject: [PATCH 196/446] gh-77782: Deprecate Py_HasFileSystemDefaultEncoding (#106272) Deprecate Py_HasFileSystemDefaultEncoding variable. --- Doc/whatsnew/3.12.rst | 1 + Include/fileobject.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b6382e7e984490..1af80ea62b392d 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1858,6 +1858,7 @@ Deprecated * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) diff --git a/Include/fileobject.h b/Include/fileobject.h index 02bd7c915a23f7..2deef544d667a5 100644 --- a/Include/fileobject.h +++ b/Include/fileobject.h @@ -23,7 +23,7 @@ Py_DEPRECATED(3.12) PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000 Py_DEPRECATED(3.12) PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors; #endif -PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; +Py_DEPRECATED(3.12) PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding; #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000 Py_DEPRECATED(3.12) PyAPI_DATA(int) Py_UTF8Mode; From 80b3d8f337bef52d7c360b4ee86be873681f747a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 12:28:59 +0200 Subject: [PATCH 197/446] gh-106023: Remove _PyObject_FastCallTstate() function (#106273) --- Doc/c-api/call.rst | 13 ------------- Include/internal/pycore_call.h | 11 +---------- Python/sysmodule.c | 12 +++++------- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/Doc/c-api/call.rst b/Doc/c-api/call.rst index 4dc66e318cd12e..ac6242701c5047 100644 --- a/Doc/c-api/call.rst +++ b/Doc/c-api/call.rst @@ -113,19 +113,6 @@ function as with any other callable. :c:func:`PyObject_Vectorcall` will usually be most efficient. -.. note:: - - In CPython 3.8, the vectorcall API and related functions were available - provisionally under names with a leading underscore: - ``_PyObject_Vectorcall``, ``_Py_TPFLAGS_HAVE_VECTORCALL``, - ``_PyObject_VectorcallMethod``, ``_PyVectorcall_Function``, - ``_PyObject_CallOneArg``, ``_PyObject_CallMethodNoArgs``, - ``_PyObject_CallMethodOneArg``. - Additionally, ``PyObject_VectorcallDict`` was available as - ``_PyObject_FastCallDict``. - The old names are still defined as aliases of the new, non-underscored names. - - Recursion Control ................. diff --git a/Include/internal/pycore_call.h b/Include/internal/pycore_call.h index 6058335cd4051a..9c32035d474b3c 100644 --- a/Include/internal/pycore_call.h +++ b/Include/internal/pycore_call.h @@ -117,8 +117,7 @@ _PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg /* === Vectorcall protocol (PEP 590) ============================= */ -// Call callable using tp_call. Arguments are like PyObject_Vectorcall() -// or PyObject_FastCallDict() (both forms are supported), +// Call callable using tp_call. Arguments are like PyObject_Vectorcall(), // except that nargs is plainly the number of arguments without flags. // // Export for shared stdlib extensions like the math extension, @@ -204,14 +203,6 @@ _PyObject_CallNoArgs(PyObject *func) { } -static inline PyObject * -_PyObject_FastCallTstate(PyThreadState *tstate, PyObject *func, - PyObject *const *args, Py_ssize_t nargs) -{ - EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func); - return _PyObject_VectorcallTstate(tstate, func, args, (size_t)nargs, NULL); -} - extern PyObject *const * _PyStack_UnpackDict(PyThreadState *tstate, PyObject *const *args, Py_ssize_t nargs, diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 8e3fbe3314a951..56d771f70ef538 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -979,12 +979,6 @@ static PyObject * call_trampoline(PyThreadState *tstate, PyObject* callback, PyFrameObject *frame, int what, PyObject *arg) { - - PyObject *stack[3]; - stack[0] = (PyObject *)frame; - stack[1] = whatstrings[what]; - stack[2] = (arg != NULL) ? arg : Py_None; - /* Discard any previous modifications the frame's fast locals */ if (frame->f_fast_as_locals) { if (PyFrame_FastToLocalsWithError(frame) < 0) { @@ -993,7 +987,11 @@ call_trampoline(PyThreadState *tstate, PyObject* callback, } /* call the Python-level function */ - PyObject *result = _PyObject_FastCallTstate(tstate, callback, stack, 3); + if (arg == NULL) { + arg = Py_None; + } + PyObject *args[3] = {(PyObject *)frame, whatstrings[what], arg}; + PyObject *result = _PyObject_VectorcallTstate(tstate, callback, args, 3, NULL); PyFrame_LocalsToFast(frame, 1); return result; From 1a2652ceaa55190a0b860abd1448095eafbdf238 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 12:39:55 +0200 Subject: [PATCH 198/446] Cleanup clear_static_tp_subclasses() (#106276) Only iterate on the dictionary if Python is built with assertions: subclass is only needed when Python is built with assertions. --- Objects/typeobject.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cc389bc3d6fa1b..e67945db9af330 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5009,6 +5009,7 @@ clear_static_tp_subclasses(PyTypeObject *type) going to leak. This mostly only affects embedding scenarios. */ +#ifndef NDEBUG // For now we just do a sanity check and then clear tp_subclasses. Py_ssize_t i = 0; PyObject *key, *ref; // borrowed ref @@ -5021,6 +5022,7 @@ clear_static_tp_subclasses(PyTypeObject *type) assert(!(subclass->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)); Py_DECREF(subclass); } +#endif clear_tp_subclasses(type); } From 319de0b578ec3dec8d30610caee3aa93f51060c7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 30 Jun 2023 12:40:09 +0200 Subject: [PATCH 199/446] GH-104584: Add Include/cpython/optimizer.h to Makefile.pre.in (#106277) --- Makefile.pre.in | 1 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index cd66c475665b2e..c1b512b94765de 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1697,6 +1697,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/object.h \ $(srcdir)/Include/cpython/objimpl.h \ $(srcdir)/Include/cpython/odictobject.h \ + $(srcdir)/Include/cpython/optimizer.h \ $(srcdir)/Include/cpython/picklebufobject.h \ $(srcdir)/Include/cpython/pthread_stubs.h \ $(srcdir)/Include/cpython/pyctype.h \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 4ccd2b5edd3f6e..c99bc905c89e21 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -162,6 +162,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 99f924856a354d..53e89457f72a37 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -393,6 +393,9 @@ Include + + Include + Include\cpython From a8ae73965b02302b7661ea07a6e4f955a961aca9 Mon Sep 17 00:00:00 2001 From: F3eQnxN3RriK Date: Fri, 30 Jun 2023 23:27:09 +0900 Subject: [PATCH 200/446] gh-101100: Docs: Fix references to several numeric dunders (#106278) Co-authored-by: Alex Waygood --- Doc/c-api/complex.rst | 10 +++++----- Doc/c-api/float.rst | 6 +++--- Doc/c-api/long.rst | 36 ++++++++++++++++++------------------ Doc/library/cmath.rst | 2 +- Doc/library/functions.rst | 32 ++++++++++++++++---------------- Doc/library/struct.rst | 4 ++-- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst index 344da903da4c1a..cb8b270fcbab6e 100644 --- a/Doc/c-api/complex.rst +++ b/Doc/c-api/complex.rst @@ -127,12 +127,12 @@ Complex Numbers as Python Objects Return the :c:type:`Py_complex` value of the complex number *op*. - If *op* is not a Python complex number object but has a :meth:`__complex__` + If *op* is not a Python complex number object but has a :meth:`~object.__complex__` method, this method will first be called to convert *op* to a Python complex - number object. If ``__complex__()`` is not defined then it falls back to - :meth:`__float__`. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. Upon failure, this method returns ``-1.0`` as a real + number object. If :meth:`!__complex__` is not defined then it falls back to + :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back + to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real value. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst index 0118bea4e720f8..fd0be1108c6300 100644 --- a/Doc/c-api/float.rst +++ b/Doc/c-api/float.rst @@ -45,14 +45,14 @@ Floating Point Objects .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat) Return a C :c:expr:`double` representation of the contents of *pyfloat*. If - *pyfloat* is not a Python floating point object but has a :meth:`__float__` + *pyfloat* is not a Python floating point object but has a :meth:`~object.__float__` method, this method will first be called to convert *pyfloat* into a float. - If ``__float__()`` is not defined then it falls back to :meth:`__index__`. + If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`. This method returns ``-1.0`` upon failure, so one should call :c:func:`PyErr_Occurred` to check for errors. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. c:function:: double PyFloat_AS_DOUBLE(PyObject *pyfloat) diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 5c1d026a330ae7..fe379ffe912391 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -121,7 +121,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: OverflowError (built-in exception) Return a C :c:expr:`long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a @@ -130,16 +130,16 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long PyLong_AsLongAndOverflow(PyObject *obj, int *overflow) Return a C :c:expr:`long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is greater than :const:`LONG_MAX` or less than @@ -150,10 +150,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long long PyLong_AsLongLong(PyObject *obj) @@ -162,7 +162,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. single: OverflowError (built-in exception) Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. Raise :exc:`OverflowError` if the value of *obj* is out of range for a @@ -171,16 +171,16 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``-1`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: long long PyLong_AsLongLongAndOverflow(PyObject *obj, int *overflow) Return a C :c:expr:`long long` representation of *obj*. If *obj* is not an - instance of :c:type:`PyLongObject`, first call its :meth:`__index__` method + instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is greater than :const:`LLONG_MAX` or less than @@ -193,10 +193,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. versionadded:: 3.2 .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong) @@ -267,7 +267,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. .. c:function:: unsigned long PyLong_AsUnsignedLongMask(PyObject *obj) Return a C :c:expr:`unsigned long` representation of *obj*. If *obj* is not - an instance of :c:type:`PyLongObject`, first call its :meth:`__index__` + an instance of :c:type:`PyLongObject`, first call its :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:expr:`unsigned long`, @@ -277,17 +277,17 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: unsigned long long PyLong_AsUnsignedLongLongMask(PyObject *obj) Return a C :c:expr:`unsigned long long` representation of *obj*. If *obj* is not an instance of :c:type:`PyLongObject`, first call its - :meth:`__index__` method (if present) to convert it to a + :meth:`~object.__index__` method (if present) to convert it to a :c:type:`PyLongObject`. If the value of *obj* is out of range for an :c:expr:`unsigned long long`, @@ -297,10 +297,10 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. to disambiguate. .. versionchanged:: 3.8 - Use :meth:`__index__` if available. + Use :meth:`~object.__index__` if available. .. versionchanged:: 3.10 - This function will no longer use :meth:`__int__`. + This function will no longer use :meth:`~object.__int__`. .. c:function:: double PyLong_AsDouble(PyObject *pylong) diff --git a/Doc/library/cmath.rst b/Doc/library/cmath.rst index b17d58e1cc0ce1..fdac51d9603ceb 100644 --- a/Doc/library/cmath.rst +++ b/Doc/library/cmath.rst @@ -9,7 +9,7 @@ This module provides access to mathematical functions for complex numbers. The functions in this module accept integers, floating-point numbers or complex numbers as arguments. They will also accept any Python object that has either a -:meth:`__complex__` or a :meth:`__float__` method: these methods are used to +:meth:`~object.__complex__` or a :meth:`~object.__float__` method: these methods are used to convert the object to a complex or floating-point number, respectively, and the function is then applied to the result of the conversion. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 3d2bb8efc95d8e..9b9731e9189853 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -122,7 +122,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to a binary string prefixed with "0b". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it - has to define an :meth:`__index__` method that returns an integer. Some + has to define an :meth:`~object.__index__` method that returns an integer. Some examples: >>> bin(3) @@ -383,9 +383,9 @@ are always available. They are listed here in alphabetical order. ``0j``. For a general Python object ``x``, ``complex(x)`` delegates to - ``x.__complex__()``. If ``__complex__()`` is not defined then it falls back - to :meth:`__float__`. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. + ``x.__complex__()``. If :meth:`~object.__complex__` is not defined then it falls back + to :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back + to :meth:`~object.__index__`. .. note:: @@ -400,8 +400,8 @@ are always available. They are listed here in alphabetical order. Grouping digits with underscores as in code literals is allowed. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__complex__` and - :meth:`__float__` are not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__complex__` and + :meth:`~object.__float__` are not defined. .. function:: delattr(object, name) @@ -681,8 +681,8 @@ are always available. They are listed here in alphabetical order. float, an :exc:`OverflowError` will be raised. For a general Python object ``x``, ``float(x)`` delegates to - ``x.__float__()``. If ``__float__()`` is not defined then it falls back - to :meth:`__index__`. + ``x.__float__()``. If :meth:`~object.__float__` is not defined then it falls back + to :meth:`~object.__index__`. If no argument is given, ``0.0`` is returned. @@ -708,7 +708,7 @@ are always available. They are listed here in alphabetical order. *x* is now a positional-only parameter. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__float__` is not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__float__` is not defined. .. index:: @@ -822,7 +822,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to a lowercase hexadecimal string prefixed with "0x". If *x* is not a Python :class:`int` object, it has to define an - :meth:`__index__` method that returns an integer. Some examples: + :meth:`~object.__index__` method that returns an integer. Some examples: >>> hex(255) '0xff' @@ -893,9 +893,9 @@ are always available. They are listed here in alphabetical order. int(x, base=10) Return an integer object constructed from a number or string *x*, or return - ``0`` if no arguments are given. If *x* defines :meth:`__int__`, - ``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`__index__`, - it returns ``x.__index__()``. If *x* defines :meth:`__trunc__`, + ``0`` if no arguments are given. If *x* defines :meth:`~object.__int__`, + ``int(x)`` returns ``x.__int__()``. If *x* defines :meth:`~object.__index__`, + it returns ``x.__index__()``. If *x* defines :meth:`~object.__trunc__`, it returns ``x.__trunc__()``. For floating point numbers, this truncates towards zero. @@ -932,10 +932,10 @@ are always available. They are listed here in alphabetical order. *x* is now a positional-only parameter. .. versionchanged:: 3.8 - Falls back to :meth:`__index__` if :meth:`__int__` is not defined. + Falls back to :meth:`~object.__index__` if :meth:`~object.__int__` is not defined. .. versionchanged:: 3.11 - The delegation to :meth:`__trunc__` is deprecated. + The delegation to :meth:`~object.__trunc__` is deprecated. .. versionchanged:: 3.11 :class:`int` string inputs and string representations can be limited to @@ -1138,7 +1138,7 @@ are always available. They are listed here in alphabetical order. Convert an integer number to an octal string prefixed with "0o". The result is a valid Python expression. If *x* is not a Python :class:`int` object, it - has to define an :meth:`__index__` method that returns an integer. For + has to define an :meth:`~object.__index__` method that returns an integer. For example: >>> oct(8) diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index 78fd6e397ae635..6d2739b4557fbf 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -266,11 +266,11 @@ Notes: (2) When attempting to pack a non-integer using any of the integer conversion - codes, if the non-integer has a :meth:`__index__` method then that method is + codes, if the non-integer has a :meth:`~object.__index__` method then that method is called to convert the argument to an integer before packing. .. versionchanged:: 3.2 - Added use of the :meth:`__index__` method for non-integers. + Added use of the :meth:`~object.__index__` method for non-integers. (3) The ``'n'`` and ``'N'`` conversion codes are only available for the native From 02ce3d56e6d230768853757109e7ca6425a6a600 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 1 Jul 2023 00:58:07 +0900 Subject: [PATCH 201/446] gh-106280: Remove unnecessary unreachable code (gh-106285) --- Python/ceval.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 2010e9e6e7a1c6..80ae85c24f0540 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2845,9 +2845,6 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject { fprintf(stderr, "Unknown uop %d, operand %" PRIu64 "\n", opcode, operand); Py_FatalError("Unknown uop"); - abort(); // Unreachable - for (;;) {} - // Really unreachable } } From 2062e115017d8c33e74ba14adef2a255c344f747 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Fri, 30 Jun 2023 22:11:10 +0300 Subject: [PATCH 202/446] gh-106267: Add type cast to generated code (#106289) --- Python/executor_cases.c.h | 2 +- Tools/cases_generator/generate_cases.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ccef2736b7120b..546b3d9f50ac76 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -187,7 +187,7 @@ case TO_BOOL_ALWAYS_TRUE: { PyObject *value = stack_pointer[-1]; PyObject *res; - uint32_t version = operand; + uint32_t version = (uint32_t)operand; #line 359 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: assert(version); diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ff88b63d3bdd80..2332d12c6c0c68 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -520,7 +520,7 @@ def write_body( f"{typ}{ceffect.name} = {func}(&next_instr[{active.offset}].cache);" ) else: - out.emit(f"{typ}{ceffect.name} = operand;") + out.emit(f"{typ}{ceffect.name} = ({typ.strip()})operand;") # Write the body, substituting a goto for ERROR_IF() and other stuff assert dedent <= 0 From 904aef994262383ae916545908f0578c2d53cf31 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 30 Jun 2023 22:39:50 +0300 Subject: [PATCH 203/446] GH-106135: Add more edge-"cases" to test_patma (GH-106271) --- Lib/test/test_patma.py | 131 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 3dbd19dfffd318..dedbc828784184 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2460,12 +2460,27 @@ class Eq: def __eq__(self, other): return True x = eq = Eq() + # None y = None match x: case None: y = 0 self.assertIs(x, eq) self.assertEqual(y, None) + # True + y = None + match x: + case True: + y = 0 + self.assertIs(x, eq) + self.assertEqual(y, None) + # False + y = None + match x: + case False: + y = 0 + self.assertIs(x, eq) + self.assertEqual(y, None) def test_patma_233(self): x = False @@ -2668,6 +2683,83 @@ def f(self, x): setattr(c, "__attr", "spam") # setattr is needed because we're in a class scope self.assertEqual(Outer().f(c), "spam") + def test_patma_250(self): + def f(x): + match x: + case {"foo": y} if y >= 0: + return True + case {"foo": y} if y < 0: + return False + + self.assertIs(f({"foo": 1}), True) + self.assertIs(f({"foo": -1}), False) + + def test_patma_251(self): + def f(v, x): + match v: + case x.attr if x.attr >= 0: + return True + case x.attr if x.attr < 0: + return False + case _: + return None + + class X: + def __init__(self, attr): + self.attr = attr + + self.assertIs(f(1, X(1)), True) + self.assertIs(f(-1, X(-1)), False) + self.assertIs(f(1, X(-1)), None) + + def test_patma_252(self): + # Side effects must be possible in guards: + effects = [] + def lt(x, y): + effects.append((x, y)) + return x < y + + res = None + match {"foo": 1}: + case {"foo": x} if lt(x, 0): + res = 0 + case {"foo": x} if lt(x, 1): + res = 1 + case {"foo": x} if lt(x, 2): + res = 2 + + self.assertEqual(res, 2) + self.assertEqual(effects, [(1, 0), (1, 1), (1, 2)]) + + def test_patma_253(self): + def f(v): + match v: + case [x] | x: + return x + + self.assertEqual(f(1), 1) + self.assertEqual(f([1]), 1) + + def test_patma_254(self): + def f(v): + match v: + case {"x": x} | x: + return x + + self.assertEqual(f(1), 1) + self.assertEqual(f({"x": 1}), 1) + + def test_patma_255(self): + x = [] + match x: + case [] as z if z.append(None): + y = 0 + case [None]: + y = 1 + self.assertEqual(x, [None]) + self.assertEqual(y, 1) + self.assertIs(z, x) + class TestSyntaxErrors(unittest.TestCase): @@ -2885,6 +2977,37 @@ def test_real_number_required_in_complex_literal_3(self): pass """) + def test_real_number_multiple_ops(self): + self.assert_syntax_error(""" + match ...: + case 0 + 0j + 0: + pass + """) + + def test_real_number_wrong_ops(self): + for op in ["*", "/", "@", "**", "%", "//"]: + with self.subTest(op=op): + self.assert_syntax_error(f""" + match ...: + case 0 {op} 0j: + pass + """) + self.assert_syntax_error(f""" + match ...: + case 0j {op} 0: + pass + """) + self.assert_syntax_error(f""" + match ...: + case -0j {op} 0: + pass + """) + self.assert_syntax_error(f""" + match ...: + case 0j {op} -0: + pass + """) + def test_wildcard_makes_remaining_patterns_unreachable_0(self): self.assert_syntax_error(""" match ...: @@ -3067,6 +3190,14 @@ class Class: self.assertIs(y, None) self.assertIs(z, None) + def test_class_pattern_not_type(self): + w = None + with self.assertRaises(TypeError): + match 1: + case max(0, 1): + w = 0 + self.assertIsNone(w) + class TestValueErrors(unittest.TestCase): From 46c1097868745eeb47abbc8af8c34e8fcb80ff1d Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 1 Jul 2023 02:45:08 +0300 Subject: [PATCH 204/446] gh-106145: Make `end_{lineno,col_offset}` required on `type_param` nodes (#106224) --- Lib/test/test_unparse.py | 2 +- ...3-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst | 2 ++ Parser/Python.asdl | 2 +- Python/Python-ast.c | 18 ++++++------------ 4 files changed, 10 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 41a6318d1499b4..b3efb61e83049e 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -705,7 +705,7 @@ class DirectoryTestCase(ASTTestCase): test_directories = (lib_dir, lib_dir / "test") run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py", "test_ast.py", "test_asdl_parser.py", "test_fstring.py", - "test_patma.py"} + "test_patma.py", "test_type_alias.py", "test_type_params.py"} _files_to_test = None diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst new file mode 100644 index 00000000000000..4f9445bbcbe550 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-29-09-46-41.gh-issue-106145.QC6-Kq.rst @@ -0,0 +1,2 @@ +Make ``end_lineno`` and ``end_col_offset`` required on ``type_param`` ast +nodes. diff --git a/Parser/Python.asdl b/Parser/Python.asdl index 93632a09f0959b..0d154867276c36 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -148,5 +148,5 @@ module Python type_param = TypeVar(identifier name, expr? bound) | ParamSpec(identifier name) | TypeVarTuple(identifier name) - attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) + attributes (int lineno, int col_offset, int end_lineno, int end_col_offset) } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 1ffb8354e3a1b1..5db9ade3af4547 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -1902,12 +1902,6 @@ init_types(struct ast_state *state) if (!state->type_param_type) return 0; if (!add_attributes(state, state->type_param_type, type_param_attributes, 4)) return 0; - if (PyObject_SetAttr(state->type_param_type, state->end_lineno, Py_None) == - -1) - return 0; - if (PyObject_SetAttr(state->type_param_type, state->end_col_offset, - Py_None) == -1) - return 0; state->TypeVar_type = make_type(state, "TypeVar", state->type_param_type, TypeVar_fields, 2, "TypeVar(identifier name, expr? bound)"); @@ -12500,9 +12494,9 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); - end_lineno = lineno; + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_lineno\" missing from type_param"); + return 1; } else { int res; @@ -12517,9 +12511,9 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } - if (tmp == NULL || tmp == Py_None) { - Py_CLEAR(tmp); - end_col_offset = col_offset; + if (tmp == NULL) { + PyErr_SetString(PyExc_TypeError, "required field \"end_col_offset\" missing from type_param"); + return 1; } else { int res; From e212618bafaa4f775502e3442de0affb80205b5e Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 1 Jul 2023 00:46:44 +0100 Subject: [PATCH 205/446] GH-89812: Simplify creation of symlinks in pathlib tests. (GH-106061) Remove `PathTest.dirlink()` function. Symlinks in `PathTest.setUp()` are created using `os.symlink()` directly; symlinks in test functions use `Path.symlink_to()` in order to make the tests applicable to a (near-)future `AbstractPath` class. --- Lib/test/test_pathlib.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index eeb522bb160523..9d3db7bfee088c 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1620,21 +1620,13 @@ def cleanup(): # Relative symlinks. os.symlink('fileA', join('linkA')) os.symlink('non-existing', join('brokenLink')) - self.dirlink('dirB', join('linkB')) - self.dirlink(os.path.join('..', 'dirB'), join('dirA', 'linkC')) + os.symlink('dirB', join('linkB'), target_is_directory=True) + os.symlink(os.path.join('..', 'dirB'), join('dirA', 'linkC'), target_is_directory=True) # This one goes upwards, creating a loop. - self.dirlink(os.path.join('..', 'dirB'), join('dirB', 'linkD')) + os.symlink(os.path.join('..', 'dirB'), join('dirB', 'linkD'), target_is_directory=True) # Broken symlink (pointing to itself). os.symlink('brokenLinkLoop', join('brokenLinkLoop')) - if os.name == 'nt': - # Workaround for http://bugs.python.org/issue13772. - def dirlink(self, src, dest): - os.symlink(src, dest, target_is_directory=True) - else: - def dirlink(self, src, dest): - os.symlink(src, dest) - def assertSame(self, path_a, path_b): self.assertTrue(os.path.samefile(str(path_a), str(path_b)), "%r and %r don't point to the same file" % @@ -2118,8 +2110,8 @@ def test_resolve_common(self): d = os_helper._longpath(tempfile.mkdtemp(suffix='-dirD', dir=os.getcwd())) self.addCleanup(os_helper.rmtree, d) - os.symlink(os.path.join(d), join('dirA', 'linkX')) - os.symlink(join('dirB'), os.path.join(d, 'linkY')) + P(BASE, 'dirA', 'linkX').symlink_to(d) + P(BASE, str(d), 'linkY').symlink_to(join('dirB')) p = P(BASE, 'dirA', 'linkX', 'linkY', 'fileB') self._check_resolve_absolute(p, P(BASE, 'dirB', 'fileB')) # Non-strict @@ -2140,9 +2132,9 @@ def test_resolve_common(self): def test_resolve_dot(self): # See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/ p = self.cls(BASE) - self.dirlink('.', join('0')) - self.dirlink(os.path.join('0', '0'), join('1')) - self.dirlink(os.path.join('1', '1'), join('2')) + p.joinpath('0').symlink_to('.', target_is_directory=True) + p.joinpath('1').symlink_to(os.path.join('0', '0'), target_is_directory=True) + p.joinpath('2').symlink_to(os.path.join('1', '1'), target_is_directory=True) q = p / '2' self.assertEqual(q.resolve(strict=True), p) r = q / '3' / '4' @@ -2320,10 +2312,10 @@ def test_parts_interning(self): def _check_complex_symlinks(self, link0_target): # Test solving a non-looping chain of symlinks (issue #19887). P = self.cls(BASE) - self.dirlink(os.path.join('link0', 'link0'), join('link1')) - self.dirlink(os.path.join('link1', 'link1'), join('link2')) - self.dirlink(os.path.join('link2', 'link2'), join('link3')) - self.dirlink(link0_target, join('link0')) + P.joinpath('link1').symlink_to(os.path.join('link0', 'link0'), target_is_directory=True) + P.joinpath('link2').symlink_to(os.path.join('link1', 'link1'), target_is_directory=True) + P.joinpath('link3').symlink_to(os.path.join('link2', 'link2'), target_is_directory=True) + P.joinpath('link0').symlink_to(link0_target, target_is_directory=True) # Resolve absolute paths. p = (P / 'link0').resolve() From eb7d6e7ad844955f9af88707d296e003c7ce4394 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 1 Jul 2023 03:04:50 +0300 Subject: [PATCH 206/446] gh-105486: Change the `repr` of `ParamSpec` list of args in `GenericAlias` (#105488) --- Lib/test/test_genericalias.py | 8 ++++ Lib/test/test_type_aliases.py | 16 ++++++++ ...-06-08-09-10-15.gh-issue-105486.dev-WS.rst | 1 + Objects/genericaliasobject.c | 38 ++++++++++++++++++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 24d4216417521c..bf600a0f4d1834 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -209,6 +209,9 @@ class MyList(list): def test_repr(self): class MyList(list): pass + class MyGeneric: + __class_getitem__ = classmethod(GenericAlias) + self.assertEqual(repr(list[str]), 'list[str]') self.assertEqual(repr(list[()]), 'list[()]') self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]') @@ -221,6 +224,11 @@ class MyList(list): self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr..MyList[int]')) self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr + # gh-105488 + self.assertTrue(repr(MyGeneric[int]).endswith('MyGeneric[int]')) + self.assertTrue(repr(MyGeneric[[]]).endswith('MyGeneric[[]]')) + self.assertTrue(repr(MyGeneric[[int, str]]).endswith('MyGeneric[[int, str]]')) + def test_exposed_type(self): import types a = types.GenericAlias(list, int) diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py index b9b24448e83d8e..0ce97f57de6860 100644 --- a/Lib/test/test_type_aliases.py +++ b/Lib/test/test_type_aliases.py @@ -142,7 +142,16 @@ def test_subscripting(self): def test_repr(self): type Simple = int + type VeryGeneric[T, *Ts, **P] = Callable[P, tuple[T, *Ts]] + self.assertEqual(repr(Simple), "Simple") + self.assertEqual(repr(VeryGeneric), "VeryGeneric") + self.assertEqual(repr(VeryGeneric[int, bytes, str, [float, object]]), + "VeryGeneric[int, bytes, str, [float, object]]") + self.assertEqual(repr(VeryGeneric[int, []]), + "VeryGeneric[int, []]") + self.assertEqual(repr(VeryGeneric[int, [VeryGeneric[int], list[str]]]), + "VeryGeneric[int, [VeryGeneric[int], list[str]]]") def test_recursive_repr(self): type Recursive = Recursive @@ -151,6 +160,13 @@ def test_recursive_repr(self): type X = list[Y] type Y = list[X] self.assertEqual(repr(X), "X") + self.assertEqual(repr(Y), "Y") + + type GenericRecursive[X] = list[X | GenericRecursive[X]] + self.assertEqual(repr(GenericRecursive), "GenericRecursive") + self.assertEqual(repr(GenericRecursive[int]), "GenericRecursive[int]") + self.assertEqual(repr(GenericRecursive[GenericRecursive[int]]), + "GenericRecursive[GenericRecursive[int]]") class TypeAliasConstructorTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst new file mode 100644 index 00000000000000..9f735db3dc89c3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-08-09-10-15.gh-issue-105486.dev-WS.rst @@ -0,0 +1 @@ +Change the repr of ``ParamSpec`` list of args in ``types.GenericAlias``. diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 888cb16edd1b46..117b4e8dfb960a 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -121,6 +121,36 @@ ga_repr_item(_PyUnicodeWriter *writer, PyObject *p) return err; } +static int +ga_repr_items_list(_PyUnicodeWriter *writer, PyObject *p) +{ + assert(PyList_CheckExact(p)); + + Py_ssize_t len = PyList_GET_SIZE(p); + + if (_PyUnicodeWriter_WriteASCIIString(writer, "[", 1) < 0) { + return -1; + } + + for (Py_ssize_t i = 0; i < len; i++) { + if (i > 0) { + if (_PyUnicodeWriter_WriteASCIIString(writer, ", ", 2) < 0) { + return -1; + } + } + PyObject *item = PyList_GET_ITEM(p, i); + if (ga_repr_item(writer, item) < 0) { + return -1; + } + } + + if (_PyUnicodeWriter_WriteASCIIString(writer, "]", 1) < 0) { + return -1; + } + + return 0; +} + static PyObject * ga_repr(PyObject *self) { @@ -148,7 +178,13 @@ ga_repr(PyObject *self) } } PyObject *p = PyTuple_GET_ITEM(alias->args, i); - if (ga_repr_item(&writer, p) < 0) { + if (PyList_CheckExact(p)) { + // Looks like we are working with ParamSpec's list of type args: + if (ga_repr_items_list(&writer, p) < 0) { + goto error; + } + } + else if (ga_repr_item(&writer, p) < 0) { goto error; } } From 04dfc6fa9018e92a5b51c29fc0ff45419c596bc3 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Fri, 30 Jun 2023 22:34:31 -0400 Subject: [PATCH 207/446] gh-106232: Make timeit doc command lines compatible with Windows. (#106296) Command Prompt (CMD Shell) and older versions of PowerShell require double quotes and single quotes inside the string. This form also works on linux and macOS. --- Doc/library/timeit.rst | 18 +++++++++--------- Doc/using/cmdline.rst | 2 +- ...3-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst | 2 ++ 3 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst diff --git a/Doc/library/timeit.rst b/Doc/library/timeit.rst index 32ab565aba0c08..a559e0a2eb3dad 100644 --- a/Doc/library/timeit.rst +++ b/Doc/library/timeit.rst @@ -27,11 +27,11 @@ can be used to compare three different expressions: .. code-block:: shell-session - $ python -m timeit '"-".join(str(n) for n in range(100))' + $ python -m timeit "'-'.join(str(n) for n in range(100))" 10000 loops, best of 5: 30.2 usec per loop - $ python -m timeit '"-".join([str(n) for n in range(100)])' + $ python -m timeit "'-'.join([str(n) for n in range(100)])" 10000 loops, best of 5: 27.5 usec per loop - $ python -m timeit '"-".join(map(str, range(100)))' + $ python -m timeit "'-'.join(map(str, range(100)))" 10000 loops, best of 5: 23.2 usec per loop This can be achieved from the :ref:`python-interface` with:: @@ -277,9 +277,9 @@ It is possible to provide a setup statement that is executed only once at the be .. code-block:: shell-session - $ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text' + $ python -m timeit -s "text = 'sample string'; char = 'g'" "char in text" 5000000 loops, best of 5: 0.0877 usec per loop - $ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)' + $ python -m timeit -s "text = 'sample string'; char = 'g'" "text.find(char)" 1000000 loops, best of 5: 0.342 usec per loop In the output, there are three fields. The loop count, which tells you how many @@ -313,14 +313,14 @@ to test for missing and present object attributes: .. code-block:: shell-session - $ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass' + $ python -m timeit "try:" " str.__bool__" "except AttributeError:" " pass" 20000 loops, best of 5: 15.7 usec per loop - $ python -m timeit 'if hasattr(str, "__bool__"): pass' + $ python -m timeit "if hasattr(str, '__bool__'): pass" 50000 loops, best of 5: 4.26 usec per loop - $ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass' + $ python -m timeit "try:" " int.__bool__" "except AttributeError:" " pass" 200000 loops, best of 5: 1.43 usec per loop - $ python -m timeit 'if hasattr(int, "__bool__"): pass' + $ python -m timeit "if hasattr(int, '__bool__'): pass" 100000 loops, best of 5: 2.23 usec per loop :: diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 9d4042ce5a7e8a..1b470d395d6d58 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -109,7 +109,7 @@ source. Many standard library modules contain code that is invoked on their execution as a script. An example is the :mod:`timeit` module:: - python -m timeit -s 'setup here' 'benchmarked code here' + python -m timeit -s "setup here" "benchmarked code here" python -m timeit -h # for details .. audit-event:: cpython.run_module module-name cmdoption-m diff --git a/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst b/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst new file mode 100644 index 00000000000000..bc16f92b7d6478 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-06-30-19-28-59.gh-issue-106232.hQ4-tz.rst @@ -0,0 +1,2 @@ +Make timeit doc command lines compatible with Windows by using double quotes +for arguments. This works on linux and macOS also. From c336b4c14fea17763ee0d3acbb8e9155beb617e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 09:54:32 +0000 Subject: [PATCH 208/446] build(deps-dev): bump mypy from 1.3.0 to 1.4.1 in /Tools/clinic (#106305) Bumps [mypy](https://github.com/python/mypy) from 1.3.0 to 1.4.1. - [Commits](https://github.com/python/mypy/compare/v1.3.0...v1.4.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Tools/clinic/requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/clinic/requirements-dev.txt b/Tools/clinic/requirements-dev.txt index 154934003c31c4..e9529f3527e95e 100644 --- a/Tools/clinic/requirements-dev.txt +++ b/Tools/clinic/requirements-dev.txt @@ -1,2 +1,2 @@ # Requirements file for external linters and checks we run on Tools/clinic/ in CI -mypy==1.3.0 +mypy==1.4.1 From d3abc9b5165eee7dbe24f8f081c0739e6ad3ef3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Jul 2023 13:23:57 +0300 Subject: [PATCH 209/446] build(deps): bump mheap/github-action-required-labels from 4 to 5 (#106306) Bumps [mheap/github-action-required-labels](https://github.com/mheap/github-action-required-labels) from 4 to 5. - [Release notes](https://github.com/mheap/github-action-required-labels/releases) - [Commits](https://github.com/mheap/github-action-required-labels/compare/v4...v5) --- updated-dependencies: - dependency-name: mheap/github-action-required-labels dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/require-pr-label.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml index 88aaea039f04f4..9327b43ae02710 100644 --- a/.github/workflows/require-pr-label.yml +++ b/.github/workflows/require-pr-label.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 10 steps: - - uses: mheap/github-action-required-labels@v4 + - uses: mheap/github-action-required-labels@v5 with: mode: exactly count: 0 From 200f2554114f3d40684af0969fef6af875cb1462 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 1 Jul 2023 11:28:07 +0100 Subject: [PATCH 210/446] gh-106149: move unconditional jump direction resolution from optimizer to assembler (#106291) --- Python/assemble.c | 34 +++++++++++++++++++++++++ Python/flowgraph.c | 22 +++++----------- Python/opcode_metadata.h | 4 +-- Tools/cases_generator/generate_cases.py | 4 +-- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/Python/assemble.c b/Python/assemble.c index 5d566a381b3988..ff7bca22286cd7 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -674,11 +674,45 @@ resolve_jump_offsets(instr_sequence *instrs) return SUCCESS; } +static int +resolve_unconditional_jumps(instr_sequence *instrs) +{ + /* Resolve directions of unconditional jumps */ + + for (int i = 0; i < instrs->s_used; i++) { + instruction *instr = &instrs->s_instrs[i]; + bool is_forward = (instr->i_oparg > i); + switch(instr->i_opcode) { + case JUMP: + assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD)); + assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD)); + instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + break; + case JUMP_NO_INTERRUPT: + assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD)); + assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT)); + instr->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + break; + default: + if (OPCODE_HAS_JUMP(instr->i_opcode) && + IS_PSEUDO_INSTR(instr->i_opcode)) { + Py_UNREACHABLE(); + } + } + } + return SUCCESS; +} + PyCodeObject * _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache, PyObject *consts, int maxdepth, instr_sequence *instrs, int nlocalsplus, int code_flags, PyObject *filename) { + + if (resolve_unconditional_jumps(instrs) < 0) { + return NULL; + } if (resolve_jump_offsets(instrs) < 0) { return NULL; } diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 429109b74beab8..213c993bb863a3 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -393,24 +393,17 @@ no_redundant_jumps(cfg_builder *g) { static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { cfg_instr *last = _PyCfg_BasicblockLastInstr(b); - if (last == NULL || !is_jump(last)) { + if (last == NULL || !is_jump(last) || + IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { return SUCCESS; } assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); + bool is_forward = last->i_target->b_visited == 0; - switch(last->i_opcode) { - case JUMP: - assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD)); - assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD)); - last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; - return SUCCESS; - case JUMP_NO_INTERRUPT: - assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD)); - assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT)); - last->i_opcode = is_forward ? - JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; - return SUCCESS; + if (is_forward) { + return SUCCESS; } + int reversed_opcode = 0; switch(last->i_opcode) { case POP_JUMP_IF_NOT_NONE: @@ -426,9 +419,6 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { reversed_opcode = POP_JUMP_IF_FALSE; break; } - if (is_forward) { - return SUCCESS; - } /* transform 'conditional jump T' to * 'reversed_jump b_next' followed by 'jump_backwards T' */ diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 5c7de77deba2d6..6a42775e091208 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -4,7 +4,7 @@ // Do not edit! -#define IS_PSEUDO_INSTR(OP) \ +#define IS_PSEUDO_INSTR(OP) ( \ ((OP) == LOAD_CLOSURE) || \ ((OP) == STORE_FAST_MAYBE_NULL) || \ ((OP) == LOAD_SUPER_METHOD) || \ @@ -17,7 +17,7 @@ ((OP) == SETUP_CLEANUP) || \ ((OP) == SETUP_WITH) || \ ((OP) == POP_BLOCK) || \ - 0 + 0) #define EXIT_TRACE 300 #define SET_IP 301 diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 2332d12c6c0c68..38be98034e0d83 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1310,10 +1310,10 @@ def write_metadata(self) -> None: def write_pseudo_instrs(self) -> None: """Write the IS_PSEUDO_INSTR macro""" - self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) \\") + self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) ( \\") for op in self.pseudos: self.out.emit(f" ((OP) == {op}) || \\") - self.out.emit(f" 0") + self.out.emit(f" 0)") def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None: """Write '#define XXX NNN' for each uop""" From 3fd99b5a974314075424744747899b2acf18dadd Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 1 Jul 2023 12:24:34 +0100 Subject: [PATCH 211/446] GH-89812: Make symlink support configurable in pathlib tests. (GH-106060) Adjust the pathlib tests to add a new `PathTest.can_symlink` class attribute, which allows us to enable or disable symlink support in tests. A (near-)future commit will add an `AbstractPath` class; its tests will hard-code the value to `True` or `False` depending on a stub subclass's capabilities. --- Lib/test/test_pathlib.py | 88 ++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 9d3db7bfee088c..a87f6c4cdc3daa 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1573,6 +1573,7 @@ class PathTest(unittest.TestCase): """Tests for the FS-accessing functionalities of the Path classes.""" cls = pathlib.Path + can_symlink = os_helper.can_symlink() # (BASE) # | @@ -1616,7 +1617,7 @@ def cleanup(): with open(join('dirC', 'dirD', 'fileD'), 'wb') as f: f.write(b"this is file D\n") os.chmod(join('dirE'), 0) - if os_helper.can_symlink(): + if self.can_symlink: # Relative symlinks. os.symlink('fileA', join('linkA')) os.symlink('non-existing', join('brokenLink')) @@ -1672,7 +1673,7 @@ def test_exists(self): self.assertIs(True, (p / 'dirA').exists()) self.assertIs(True, (p / 'fileA').exists()) self.assertIs(False, (p / 'fileA' / 'bah').exists()) - if os_helper.can_symlink(): + if self.can_symlink: self.assertIs(True, (p / 'linkA').exists()) self.assertIs(True, (p / 'linkB').exists()) self.assertIs(True, (p / 'linkB' / 'fileB').exists()) @@ -1739,12 +1740,13 @@ def test_iterdir(self): it = p.iterdir() paths = set(it) expected = ['dirA', 'dirB', 'dirC', 'dirE', 'fileA'] - if os_helper.can_symlink(): + if self.can_symlink: expected += ['linkA', 'linkB', 'brokenLink', 'brokenLinkLoop'] self.assertEqual(paths, { P(BASE, q) for q in expected }) - @os_helper.skip_unless_symlink def test_iterdir_symlink(self): + if not self.can_symlink: + self.skipTest("symlinks required") # __iter__ on a symlink to a directory. P = self.cls p = P(BASE, 'linkB') @@ -1772,23 +1774,23 @@ def _check(glob, expected): _check(it, ["fileA"]) _check(p.glob("fileB"), []) _check(p.glob("dir*/file*"), ["dirB/fileB", "dirC/fileC"]) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.glob("*A"), ['dirA', 'fileA']) else: _check(p.glob("*A"), ['dirA', 'fileA', 'linkA']) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.glob("*B/*"), ['dirB/fileB']) else: _check(p.glob("*B/*"), ['dirB/fileB', 'dirB/linkD', 'linkB/fileB', 'linkB/linkD']) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.glob("*/fileB"), ['dirB/fileB']) else: _check(p.glob("*/fileB"), ['dirB/fileB', 'linkB/fileB']) - if os_helper.can_symlink(): + if self.can_symlink: _check(p.glob("brokenLink"), ['brokenLink']) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"]) else: _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"]) @@ -1810,8 +1812,9 @@ def _check(path, pattern, case_sensitive, expected): _check(path, "dirb/file*", True, []) _check(path, "dirb/file*", False, ["dirB/fileB"]) - @os_helper.skip_unless_symlink def test_glob_follow_symlinks_common(self): + if not self.can_symlink: + self.skipTest("symlinks required") def _check(path, glob, expected): actual = {path for path in path.glob(glob, follow_symlinks=True) if "linkD" not in path.parent.parts} # exclude symlink loop. @@ -1835,8 +1838,9 @@ def _check(path, glob, expected): _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD"]) _check(p, "*/dirD/**/", ["dirC/dirD"]) - @os_helper.skip_unless_symlink def test_glob_no_follow_symlinks_common(self): + if not self.can_symlink: + self.skipTest("symlinks required") def _check(path, glob, expected): actual = {path for path in path.glob(glob, follow_symlinks=False)} self.assertEqual(actual, { P(BASE, q) for q in expected }) @@ -1868,14 +1872,14 @@ def _check(glob, expected): _check(p.rglob("fileB"), ["dirB/fileB"]) _check(p.rglob("**/fileB"), ["dirB/fileB"]) _check(p.rglob("*/fileA"), []) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.rglob("*/fileB"), ["dirB/fileB"]) else: _check(p.rglob("*/fileB"), ["dirB/fileB", "dirB/linkD/fileB", "linkB/fileB", "dirA/linkC/fileB"]) _check(p.rglob("file*"), ["fileA", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD"]) - if not os_helper.can_symlink(): + if not self.can_symlink: _check(p.rglob("*/"), [ "dirA", "dirB", "dirC", "dirC/dirD", "dirE", ]) @@ -1900,8 +1904,9 @@ def _check(glob, expected): _check(p.rglob("*.txt"), ["dirC/novel.txt"]) _check(p.rglob("*.*"), ["dirC/novel.txt"]) - @os_helper.skip_unless_symlink def test_rglob_follow_symlinks_common(self): + if not self.can_symlink: + self.skipTest("symlinks required") def _check(path, glob, expected): actual = {path for path in path.rglob(glob, follow_symlinks=True) if 'linkD' not in path.parent.parts} # exclude symlink loop. @@ -1929,8 +1934,9 @@ def _check(path, glob, expected): _check(p, "*.txt", ["dirC/novel.txt"]) _check(p, "*.*", ["dirC/novel.txt"]) - @os_helper.skip_unless_symlink def test_rglob_no_follow_symlinks_common(self): + if not self.can_symlink: + self.skipTest("symlinks required") def _check(path, glob, expected): actual = {path for path in path.rglob(glob, follow_symlinks=False)} self.assertEqual(actual, { P(BASE, q) for q in expected }) @@ -1954,9 +1960,10 @@ def _check(path, glob, expected): _check(p, "*.txt", ["dirC/novel.txt"]) _check(p, "*.*", ["dirC/novel.txt"]) - @os_helper.skip_unless_symlink def test_rglob_symlink_loop(self): # Don't get fooled by symlink loops (Issue #26012). + if not self.can_symlink: + self.skipTest("symlinks required") P = self.cls p = P(BASE) given = set(p.rglob('*')) @@ -2003,9 +2010,10 @@ def test_glob_dotdot(self): self.assertEqual(set(p.glob("xyzzy/..")), set()) self.assertEqual(set(p.glob("/".join([".."] * 50))), { P(BASE, *[".."] * 50)}) - @os_helper.skip_unless_symlink def test_glob_permissions(self): # See bpo-38894 + if not self.can_symlink: + self.skipTest("symlinks required") P = self.cls base = P(BASE) / 'permissions' base.mkdir() @@ -2023,9 +2031,10 @@ def test_glob_permissions(self): self.assertEqual(len(set(base.glob("*/fileC"))), 50) self.assertEqual(len(set(base.glob("*/file*"))), 50) - @os_helper.skip_unless_symlink def test_glob_long_symlink(self): # See gh-87695 + if not self.can_symlink: + self.skipTest("symlinks required") base = self.cls(BASE) / 'long_symlink' base.mkdir() bad_link = base / 'bad_link' @@ -2043,8 +2052,9 @@ def test_glob_above_recursion_limit(self): with set_recursion_limit(recursion_limit): list(base.glob('**')) - @os_helper.skip_unless_symlink def test_readlink(self): + if not self.can_symlink: + self.skipTest("symlinks required") P = self.cls(BASE) self.assertEqual((P / 'linkA').readlink(), self.cls('fileA')) self.assertEqual((P / 'brokenLink').readlink(), @@ -2067,8 +2077,9 @@ def _check_resolve(self, p, expected, strict=True): # This can be used to check both relative and absolute resolutions. _check_resolve_relative = _check_resolve_absolute = _check_resolve - @os_helper.skip_unless_symlink def test_resolve_common(self): + if not self.can_symlink: + self.skipTest("symlinks required") P = self.cls p = P(BASE, 'foo') with self.assertRaises(OSError) as cm: @@ -2128,9 +2139,10 @@ def test_resolve_common(self): # resolves to 'dirB/..' first before resolving to parent of dirB. self._check_resolve_relative(p, P(BASE, 'foo', 'in', 'spam'), False) - @os_helper.skip_unless_symlink def test_resolve_dot(self): # See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/ + if not self.can_symlink: + self.skipTest("symlinks required") p = self.cls(BASE) p.joinpath('0').symlink_to('.', target_is_directory=True) p.joinpath('1').symlink_to(os.path.join('0', '0'), target_is_directory=True) @@ -2152,8 +2164,9 @@ def test_stat(self): self.addCleanup(p.chmod, st.st_mode) self.assertNotEqual(p.stat(), st) - @os_helper.skip_unless_symlink def test_stat_no_follow_symlinks(self): + if not self.can_symlink: + self.skipTest("symlinks required") p = self.cls(BASE) / 'linkA' st = p.stat() self.assertNotEqual(st, p.stat(follow_symlinks=False)) @@ -2163,8 +2176,9 @@ def test_stat_no_follow_symlinks_nosymlink(self): st = p.stat() self.assertEqual(st, p.stat(follow_symlinks=False)) - @os_helper.skip_unless_symlink def test_lstat(self): + if not self.can_symlink: + self.skipTest("symlinks required") p = self.cls(BASE)/ 'linkA' st = p.stat() self.assertNotEqual(st, p.lstat()) @@ -2180,7 +2194,7 @@ def test_is_dir(self): self.assertFalse((P / 'fileA').is_dir()) self.assertFalse((P / 'non-existing').is_dir()) self.assertFalse((P / 'fileA' / 'bah').is_dir()) - if os_helper.can_symlink(): + if self.can_symlink: self.assertFalse((P / 'linkA').is_dir()) self.assertTrue((P / 'linkB').is_dir()) self.assertFalse((P/ 'brokenLink').is_dir()) @@ -2193,7 +2207,7 @@ def test_is_dir_no_follow_symlinks(self): self.assertFalse((P / 'fileA').is_dir(follow_symlinks=False)) self.assertFalse((P / 'non-existing').is_dir(follow_symlinks=False)) self.assertFalse((P / 'fileA' / 'bah').is_dir(follow_symlinks=False)) - if os_helper.can_symlink(): + if self.can_symlink: self.assertFalse((P / 'linkA').is_dir(follow_symlinks=False)) self.assertFalse((P / 'linkB').is_dir(follow_symlinks=False)) self.assertFalse((P/ 'brokenLink').is_dir(follow_symlinks=False)) @@ -2206,7 +2220,7 @@ def test_is_file(self): self.assertFalse((P / 'dirA').is_file()) self.assertFalse((P / 'non-existing').is_file()) self.assertFalse((P / 'fileA' / 'bah').is_file()) - if os_helper.can_symlink(): + if self.can_symlink: self.assertTrue((P / 'linkA').is_file()) self.assertFalse((P / 'linkB').is_file()) self.assertFalse((P/ 'brokenLink').is_file()) @@ -2219,7 +2233,7 @@ def test_is_file_no_follow_symlinks(self): self.assertFalse((P / 'dirA').is_file(follow_symlinks=False)) self.assertFalse((P / 'non-existing').is_file(follow_symlinks=False)) self.assertFalse((P / 'fileA' / 'bah').is_file(follow_symlinks=False)) - if os_helper.can_symlink(): + if self.can_symlink: self.assertFalse((P / 'linkA').is_file(follow_symlinks=False)) self.assertFalse((P / 'linkB').is_file(follow_symlinks=False)) self.assertFalse((P/ 'brokenLink').is_file(follow_symlinks=False)) @@ -2237,7 +2251,7 @@ def test_is_mount(self): self.assertFalse((P / 'non-existing').is_mount()) self.assertFalse((P / 'fileA' / 'bah').is_mount()) self.assertTrue(R.is_mount()) - if os_helper.can_symlink(): + if self.can_symlink: self.assertFalse((P / 'linkA').is_mount()) self.assertIs((R / '\udfff').is_mount(), False) @@ -2247,13 +2261,13 @@ def test_is_symlink(self): self.assertFalse((P / 'dirA').is_symlink()) self.assertFalse((P / 'non-existing').is_symlink()) self.assertFalse((P / 'fileA' / 'bah').is_symlink()) - if os_helper.can_symlink(): + if self.can_symlink: self.assertTrue((P / 'linkA').is_symlink()) self.assertTrue((P / 'linkB').is_symlink()) self.assertTrue((P/ 'brokenLink').is_symlink()) self.assertIs((P / 'fileA\udfff').is_file(), False) self.assertIs((P / 'fileA\x00').is_file(), False) - if os_helper.can_symlink(): + if self.can_symlink: self.assertIs((P / 'linkA\udfff').is_file(), False) self.assertIs((P / 'linkA\x00').is_file(), False) @@ -2310,6 +2324,9 @@ def test_parts_interning(self): self.assertIs(p.parts[2], q.parts[3]) def _check_complex_symlinks(self, link0_target): + if not self.can_symlink: + self.skipTest("symlinks required") + # Test solving a non-looping chain of symlinks (issue #19887). P = self.cls(BASE) P.joinpath('link1').symlink_to(os.path.join('link0', 'link0'), target_is_directory=True) @@ -2350,15 +2367,12 @@ def _check_complex_symlinks(self, link0_target): finally: os.chdir(old_path) - @os_helper.skip_unless_symlink def test_complex_symlinks_absolute(self): self._check_complex_symlinks(BASE) - @os_helper.skip_unless_symlink def test_complex_symlinks_relative(self): self._check_complex_symlinks('.') - @os_helper.skip_unless_symlink def test_complex_symlinks_relative_dot_dot(self): self._check_complex_symlinks(os.path.join('dirA', '..')) @@ -2462,7 +2476,7 @@ def with_segments(self, *pathsegments): self.assertEqual(42, p.with_segments('~').expanduser().session_id) self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id) self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id) - if os_helper.can_symlink(): + if self.can_symlink: self.assertEqual(42, (p / 'linkA').readlink().session_id) for path in p.iterdir(): self.assertEqual(42, path.session_id) @@ -2783,8 +2797,9 @@ def my_mkdir(path, mode=0o777): self.assertNotIn(str(p12), concurrently_created) self.assertTrue(p.exists()) - @os_helper.skip_unless_symlink def test_symlink_to(self): + if not self.can_symlink: + self.skipTest("symlinks required") P = self.cls(BASE) target = P / 'fileA' # Symlinking a path target. @@ -3167,8 +3182,9 @@ def test_touch_mode(self): st = os.stat(join('masked_new_file')) self.assertEqual(stat.S_IMODE(st.st_mode), 0o750) - @os_helper.skip_unless_symlink def test_resolve_loop(self): + if not self.can_symlink: + self.skipTest("symlinks required") # Loops with relative symlinks. os.symlink('linkX/inside', join('linkX')) self._check_symlink_loop(BASE, 'linkX') From 6e01055e15c252185b118956d545bfad03ae11ed Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 1 Jul 2023 12:58:30 +0100 Subject: [PATCH 212/446] GH-89812: Test that `pathlib.Path.is_junction()` returns false (GH-106062) Slightly expand the test coverage of `is_junction()`. The existing test only checks that `os.path.isjunction()` is called under-the-hood. --- Lib/test/test_pathlib.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index a87f6c4cdc3daa..441a7bcd4d4199 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2271,6 +2271,15 @@ def test_is_symlink(self): self.assertIs((P / 'linkA\udfff').is_file(), False) self.assertIs((P / 'linkA\x00').is_file(), False) + def test_is_junction_false(self): + P = self.cls(BASE) + self.assertFalse((P / 'fileA').is_junction()) + self.assertFalse((P / 'dirA').is_junction()) + self.assertFalse((P / 'non-existing').is_junction()) + self.assertFalse((P / 'fileA' / 'bah').is_junction()) + self.assertFalse((P / 'fileA\udfff').is_junction()) + self.assertFalse((P / 'fileA\x00').is_junction()) + def test_is_fifo_false(self): P = self.cls(BASE) self.assertFalse((P / 'fileA').is_fifo()) From cbc33e4aede10f4d5799d9f7aa9ec5b91414f65b Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 1 Jul 2023 13:29:02 +0100 Subject: [PATCH 213/446] GH-89812: Miscellaneous pathlib test improvements (GH-106063) - Split out dedicated test for unbuffered `open()` - Split out dedicated test for `is_mount()` at the filesystem root - Avoid `os.stat()` when checking that empty paths point to '.' - Remove unnecessary `rmtree()` call - Remove unused `assertSame()` method --- Lib/test/test_pathlib.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 441a7bcd4d4199..5be5a77721baa8 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1628,11 +1628,6 @@ def cleanup(): # Broken symlink (pointing to itself). os.symlink('brokenLinkLoop', join('brokenLinkLoop')) - def assertSame(self, path_a, path_b): - self.assertTrue(os.path.samefile(str(path_a), str(path_b)), - "%r and %r don't point to the same file" % - (path_a, path_b)) - def assertFileNotFound(self, func, *args, **kwargs): with self.assertRaises(FileNotFoundError) as cm: func(*args, **kwargs) @@ -1664,7 +1659,7 @@ def test_samefile(self): def test_empty_path(self): # The empty path points to '.' p = self.cls('') - self.assertEqual(p.stat(), os.stat('.')) + self.assertEqual(str(p), '.') def test_exists(self): P = self.cls @@ -1693,9 +1688,6 @@ def test_open_common(self): with (p / 'fileA').open('rb') as f: self.assertIsInstance(f, io.BufferedIOBase) self.assertEqual(f.read().strip(), b"this is file A") - with (p / 'fileA').open('rb', buffering=0) as f: - self.assertIsInstance(f, io.RawIOBase) - self.assertEqual(f.read().strip(), b"this is file A") def test_read_write_bytes(self): p = self.cls(BASE) @@ -2017,7 +2009,6 @@ def test_glob_permissions(self): P = self.cls base = P(BASE) / 'permissions' base.mkdir() - self.addCleanup(os_helper.rmtree, base) for i in range(100): link = base / f"link{i}" @@ -2045,8 +2036,8 @@ def test_glob_above_recursion_limit(self): recursion_limit = 50 # directory_depth > recursion_limit directory_depth = recursion_limit + 10 - base = pathlib.Path(os_helper.TESTFN, 'deep') - path = pathlib.Path(base, *(['d'] * directory_depth)) + base = self.cls(BASE, 'deep') + path = self.cls(base, *(['d'] * directory_depth)) path.mkdir(parents=True) with set_recursion_limit(recursion_limit): @@ -2242,18 +2233,12 @@ def test_is_file_no_follow_symlinks(self): def test_is_mount(self): P = self.cls(BASE) - if os.name == 'nt': - R = self.cls('c:\\') - else: - R = self.cls('/') self.assertFalse((P / 'fileA').is_mount()) self.assertFalse((P / 'dirA').is_mount()) self.assertFalse((P / 'non-existing').is_mount()) self.assertFalse((P / 'fileA' / 'bah').is_mount()) - self.assertTrue(R.is_mount()) if self.can_symlink: self.assertFalse((P / 'linkA').is_mount()) - self.assertIs((R / '\udfff').is_mount(), False) def test_is_symlink(self): P = self.cls(BASE) @@ -2496,6 +2481,12 @@ def with_segments(self, *pathsegments): for dirpath, dirnames, filenames in p.walk(): self.assertEqual(42, dirpath.session_id) + def test_open_unbuffered(self): + p = self.cls(BASE) + with (p / 'fileA').open('rb', buffering=0) as f: + self.assertIsInstance(f, io.RawIOBase) + self.assertEqual(f.read().strip(), b"this is file A") + def test_resolve_nonexist_relative_issue38671(self): p = self.cls('non', 'exist') @@ -2896,6 +2887,14 @@ def test_is_char_device_true(self): self.assertIs(self.cls('/dev/null\udfff').is_char_device(), False) self.assertIs(self.cls('/dev/null\x00').is_char_device(), False) + def test_is_mount_root(self): + if os.name == 'nt': + R = self.cls('c:\\') + else: + R = self.cls('/') + self.assertTrue(R.is_mount()) + self.assertFalse((R / '\udfff').is_mount()) + def test_passing_kwargs_deprecated(self): with self.assertWarns(DeprecationWarning): self.cls(foo="bar") From c2622a0d82078a7ab17597707b4dd42446a043ae Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sat, 1 Jul 2023 13:33:29 +0100 Subject: [PATCH 214/446] GH-89812: Improve test for `pathlib.Path.stat()` (GH-106064) Make assertions about the `st_mode`, `st_ino` and `st_dev` attributes of the stat results from two files and a directory, rather than checking if `chmod()` affects `st_mode` (which is already tested elsewhere). --- Lib/test/test_pathlib.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 5be5a77721baa8..464a835212d472 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2145,15 +2145,25 @@ def test_resolve_dot(self): # Non-strict self.assertEqual(r.resolve(strict=False), p / '3' / '4') - @os_helper.skip_unless_working_chmod def test_stat(self): - p = self.cls(BASE) / 'fileA' - st = p.stat() - self.assertEqual(p.stat(), st) - # Change file mode by flipping write bit. - p.chmod(st.st_mode ^ 0o222) - self.addCleanup(p.chmod, st.st_mode) - self.assertNotEqual(p.stat(), st) + statA = self.cls(BASE).joinpath('fileA').stat() + statB = self.cls(BASE).joinpath('dirB', 'fileB').stat() + statC = self.cls(BASE).joinpath('dirC').stat() + # st_mode: files are the same, directory differs. + self.assertIsInstance(statA.st_mode, int) + self.assertEqual(statA.st_mode, statB.st_mode) + self.assertNotEqual(statA.st_mode, statC.st_mode) + self.assertNotEqual(statB.st_mode, statC.st_mode) + # st_ino: all different, + self.assertIsInstance(statA.st_ino, int) + self.assertNotEqual(statA.st_ino, statB.st_ino) + self.assertNotEqual(statA.st_ino, statC.st_ino) + self.assertNotEqual(statB.st_ino, statC.st_ino) + # st_dev: all the same. + self.assertIsInstance(statA.st_dev, int) + self.assertEqual(statA.st_dev, statB.st_dev) + self.assertEqual(statA.st_dev, statC.st_dev) + # other attributes not used by pathlib. def test_stat_no_follow_symlinks(self): if not self.can_symlink: From 822db860eada721742f878653d7ac9364ed8df59 Mon Sep 17 00:00:00 2001 From: Md Sadman Chowdhury <61442059+SpicyCatGames@users.noreply.github.com> Date: Sun, 2 Jul 2023 01:47:14 +0600 Subject: [PATCH 215/446] Fix duplicate word typos in comments (#106225) --- Include/cpython/object.h | 2 +- Objects/frameobject.c | 2 +- Python/initconfig.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 71d268fae1a6dc..d681435c845459 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -231,7 +231,7 @@ struct _typeobject { }; /* This struct is used by the specializer - * It should should be treated as an opaque blob + * It should be treated as an opaque blob * by code other than the specializer and interpreter. */ struct _specialization_cache { // In order to avoid bloating the bytecode with lots of inline caches, the diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 98f4a0378bf76d..0158d72d6b4f98 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1186,7 +1186,7 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i, // (likely) MAKE_CELL must have executed already. value = PyCell_GET(value); } - // (likely) Otherwise it it is an arg (kind & CO_FAST_LOCAL), + // (likely) Otherwise it is an arg (kind & CO_FAST_LOCAL), // with the initial value set when the frame was created... // (unlikely) ...or it was set to some initial value by // an earlier call to PyFrame_LocalsToFast(). diff --git a/Python/initconfig.c b/Python/initconfig.c index 1dcefd478eefea..147cb370412cd6 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -538,7 +538,7 @@ _Py_SetArgcArgv(Py_ssize_t argc, wchar_t * const *argv) _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc); // XXX _PyRuntime.orig_argv only gets cleared by Py_Main(), - // so it it currently leaks for embedders. + // so it currently leaks for embedders. res = _PyWideStringList_Copy(&_PyRuntime.orig_argv, &argv_list); PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); From 46d77610fc77088bceac720a13d9f2df3a50f29e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 00:27:18 +0200 Subject: [PATCH 216/446] gh-106316: Remove pytime.h header file (#106317) Remove the "cpython/pytime.h" header file: it only contained private functions. Move functions to the internal pycore_time.h header file. Move tests from _testcapi to _testinternalcapi. Rename also test methods to have the same name than tested C functions. No longer export these functions: * _PyTime_Add() * _PyTime_As100Nanoseconds() * _PyTime_FromMicrosecondsClamp() * _PyTime_FromTimespec() * _PyTime_FromTimeval() * _PyTime_GetPerfCounterWithInfo() * _PyTime_MulDiv() --- .github/CODEOWNERS | 2 +- Doc/whatsnew/3.13.rst | 3 + Include/Python.h | 1 - Include/cpython/pytime.h | 331 ------------------ Include/internal/pycore_import.h | 2 + Include/internal/pycore_time.h | 312 +++++++++++++++++ Lib/test/test_time.py | 89 ++--- Makefile.pre.in | 1 - ...-07-01-21-23-33.gh-issue-106316.hp2Ijw.rst | 2 + Modules/Setup.stdlib.in | 2 +- Modules/_queuemodule.c | 1 + Modules/_testcapi/parts.h | 1 - Modules/_testcapi/pytime.c | 274 --------------- Modules/_testcapimodule.c | 3 - Modules/_testinternalcapi.c | 266 ++++++++++++++ Modules/_testsinglephase.c | 1 + Modules/selectmodule.c | 1 + Modules/socketmodule.h | 2 + PCbuild/_testcapi.vcxproj | 3 +- PCbuild/_testcapi.vcxproj.filters | 5 +- PCbuild/pythoncore.vcxproj | 1 - PCbuild/pythoncore.vcxproj.filters | 3 - Python/pytime.c | 1 + Tools/build/stable_abi.py | 1 - Tools/c-analyzer/c_parser/preprocessor/gcc.py | 9 +- 25 files changed, 650 insertions(+), 667 deletions(-) delete mode 100644 Include/cpython/pytime.h create mode 100644 Misc/NEWS.d/next/C API/2023-07-01-21-23-33.gh-issue-106316.hp2Ijw.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26efa5083672ec..c044e9b8f88c58 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -79,7 +79,7 @@ Doc/library/time.rst @pganssle @abalkin Lib/test/test_time.py @pganssle @abalkin Modules/timemodule.c @pganssle @abalkin Python/pytime.c @pganssle @abalkin -Include/pytime.h @pganssle @abalkin +Include/internal/pycore_time.h @pganssle @abalkin # Email and related **/*mail* @python/email-team diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 9696dd4ff0b700..628945f7d5804f 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -602,3 +602,6 @@ Removed use ``PyObject_Vectorcall()`` which is available since Python 3.8 (:pep:`590`). (Contributed by Victor Stinner in :gh:`106023`.) + +* Remove ``cpython/pytime.h`` header file: it only contained private functions. + (Contributed by Victor Stinner in :gh:`106316`.) diff --git a/Include/Python.h b/Include/Python.h index 45ba2ec12f2ad2..183d07cc539b4a 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -83,7 +83,6 @@ #include "weakrefobject.h" #include "structseq.h" #include "cpython/picklebufobject.h" -#include "cpython/pytime.h" #include "codecs.h" #include "pyerrors.h" #include "pythread.h" diff --git a/Include/cpython/pytime.h b/Include/cpython/pytime.h deleted file mode 100644 index 16d88d191e9e25..00000000000000 --- a/Include/cpython/pytime.h +++ /dev/null @@ -1,331 +0,0 @@ -// The _PyTime_t API is written to use timestamp and timeout values stored in -// various formats and to read clocks. -// -// The _PyTime_t type is an integer to support directly common arithmetic -// operations like t1 + t2. -// -// The _PyTime_t API supports a resolution of 1 nanosecond. The _PyTime_t type -// is signed to support negative timestamps. The supported range is around -// [-292.3 years; +292.3 years]. Using the Unix epoch (January 1st, 1970), the -// supported date range is around [1677-09-21; 2262-04-11]. -// -// Formats: -// -// * seconds -// * seconds as a floating pointer number (C double) -// * milliseconds (10^-3 seconds) -// * microseconds (10^-6 seconds) -// * 100 nanoseconds (10^-7 seconds) -// * nanoseconds (10^-9 seconds) -// * timeval structure, 1 microsecond resolution (10^-6 seconds) -// * timespec structure, 1 nanosecond resolution (10^-9 seconds) -// -// Integer overflows are detected and raise OverflowError. Conversion to a -// resolution worse than 1 nanosecond is rounded correctly with the requested -// rounding mode. There are 4 rounding modes: floor (towards -inf), ceiling -// (towards +inf), half even and up (away from zero). -// -// Some functions clamp the result in the range [_PyTime_MIN; _PyTime_MAX], so -// the caller doesn't have to handle errors and doesn't need to hold the GIL. -// For example, _PyTime_Add(t1, t2) computes t1+t2 and clamp the result on -// overflow. -// -// Clocks: -// -// * System clock -// * Monotonic clock -// * Performance counter -// -// Operations like (t * k / q) with integers are implemented in a way to reduce -// the risk of integer overflow. Such operation is used to convert a clock -// value expressed in ticks with a frequency to _PyTime_t, like -// QueryPerformanceCounter() with QueryPerformanceFrequency(). - -#ifndef Py_LIMITED_API -#ifndef Py_PYTIME_H -#define Py_PYTIME_H - -/************************************************************************** -Symbols and macros to supply platform-independent interfaces to time related -functions and constants -**************************************************************************/ -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __clang__ -struct timeval; -#endif - -/* _PyTime_t: Python timestamp with subsecond precision. It can be used to - store a duration, and so indirectly a date (related to another date, like - UNIX epoch). */ -typedef int64_t _PyTime_t; -// _PyTime_MIN nanoseconds is around -292.3 years -#define _PyTime_MIN INT64_MIN -// _PyTime_MAX nanoseconds is around +292.3 years -#define _PyTime_MAX INT64_MAX -#define _SIZEOF_PYTIME_T 8 - -typedef enum { - /* Round towards minus infinity (-inf). - For example, used to read a clock. */ - _PyTime_ROUND_FLOOR=0, - /* Round towards infinity (+inf). - For example, used for timeout to wait "at least" N seconds. */ - _PyTime_ROUND_CEILING=1, - /* Round to nearest with ties going to nearest even integer. - For example, used to round from a Python float. */ - _PyTime_ROUND_HALF_EVEN=2, - /* Round away from zero - For example, used for timeout. _PyTime_ROUND_CEILING rounds - -1e-9 to 0 milliseconds which causes bpo-31786 issue. - _PyTime_ROUND_UP rounds -1e-9 to -1 millisecond which keeps - the timeout sign as expected. select.poll(timeout) must block - for negative values." */ - _PyTime_ROUND_UP=3, - /* _PyTime_ROUND_TIMEOUT (an alias for _PyTime_ROUND_UP) should be - used for timeouts. */ - _PyTime_ROUND_TIMEOUT = _PyTime_ROUND_UP -} _PyTime_round_t; - - -/* Convert a time_t to a PyLong. */ -PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( - time_t sec); - -/* Convert a PyLong to a time_t. */ -PyAPI_FUNC(time_t) _PyLong_AsTime_t( - PyObject *obj); - -/* Convert a number of seconds, int or float, to time_t. */ -PyAPI_FUNC(int) _PyTime_ObjectToTime_t( - PyObject *obj, - time_t *sec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timeval structure. - usec is in the range [0; 999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimeval( - PyObject *obj, - time_t *sec, - long *usec, - _PyTime_round_t); - -/* Convert a number of seconds, int or float, to a timespec structure. - nsec is in the range [0; 999999999] and rounded towards zero. - For example, -1.2 is converted to (-2, 800000000). */ -PyAPI_FUNC(int) _PyTime_ObjectToTimespec( - PyObject *obj, - time_t *sec, - long *nsec, - _PyTime_round_t); - - -/* Create a timestamp from a number of seconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); - -/* Macro to create a timestamp from a number of seconds, no integer overflow. - Only use the macro for small values, prefer _PyTime_FromSeconds(). */ -#define _PYTIME_FROMSECONDS(seconds) \ - ((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) - -/* Create a timestamp from a number of nanoseconds. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(_PyTime_t ns); - -/* Create a timestamp from a number of microseconds. - * Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. */ -PyAPI_FUNC(_PyTime_t) _PyTime_FromMicrosecondsClamp(_PyTime_t us); - -/* Create a timestamp from nanoseconds (Python int). */ -PyAPI_FUNC(int) _PyTime_FromNanosecondsObject(_PyTime_t *t, - PyObject *obj); - -/* Convert a number of seconds (Python float or int) to a timestamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromSecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a number of milliseconds (Python float or int, 10^-3) to a timestamp. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromMillisecondsObject(_PyTime_t *t, - PyObject *obj, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds as a C double. */ -PyAPI_FUNC(double) _PyTime_AsSecondsDouble(_PyTime_t t); - -/* Convert timestamp to a number of milliseconds (10^-3 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of microseconds (10^-6 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, - _PyTime_round_t round); - -/* Convert timestamp to a number of nanoseconds (10^-9 seconds). */ -PyAPI_FUNC(_PyTime_t) _PyTime_AsNanoseconds(_PyTime_t t); - -#ifdef MS_WINDOWS -// Convert timestamp to a number of 100 nanoseconds (10^-7 seconds). -PyAPI_FUNC(_PyTime_t) _PyTime_As100Nanoseconds(_PyTime_t t, - _PyTime_round_t round); -#endif - -/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int - object. */ -PyAPI_FUNC(PyObject *) _PyTime_AsNanosecondsObject(_PyTime_t t); - -#ifndef MS_WINDOWS -/* Create a timestamp from a timeval structure. - Raise an exception and return -1 on overflow, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv); -#endif - -/* Convert a timestamp to a timeval structure (microsecond resolution). - tv_usec is always positive. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Similar to _PyTime_AsTimeval() but don't raise an exception on overflow. - On overflow, clamp tv_sec to _PyTime_t min/max. */ -PyAPI_FUNC(void) _PyTime_AsTimeval_clamp(_PyTime_t t, - struct timeval *tv, - _PyTime_round_t round); - -/* Convert a timestamp to a number of seconds (secs) and microseconds (us). - us is always positive. This function is similar to _PyTime_AsTimeval() - except that secs is always a time_t type, whereas the timeval structure - uses a C long for tv_sec on Windows. - Raise an exception and return -1 if the conversion overflowed, - return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( - _PyTime_t t, - time_t *secs, - int *us, - _PyTime_round_t round); - -#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) -/* Create a timestamp from a timespec structure. - Raise an exception and return -1 on overflow, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts); - -/* Convert a timestamp to a timespec structure (nanosecond resolution). - tv_nsec is always positive. - Raise an exception and return -1 on error, return 0 on success. */ -PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); - -/* Similar to _PyTime_AsTimespec() but don't raise an exception on overflow. - On overflow, clamp tv_sec to _PyTime_t min/max. */ -PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts); -#endif - - -// Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. -PyAPI_FUNC(_PyTime_t) _PyTime_Add(_PyTime_t t1, _PyTime_t t2); - -/* Compute ticks * mul / div. - Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. - The caller must ensure that ((div - 1) * mul) cannot overflow. */ -PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks, - _PyTime_t mul, - _PyTime_t div); - -/* Structure used by time.get_clock_info() */ -typedef struct { - const char *implementation; - int monotonic; - int adjustable; - double resolution; -} _Py_clock_info_t; - -/* Get the current time from the system clock. - - If the internal clock fails, silently ignore the error and return 0. - On integer overflow, silently ignore the overflow and clamp the clock to - [_PyTime_MIN; _PyTime_MAX]. - - Use _PyTime_GetSystemClockWithInfo() to check for failure. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void); - -/* Get the current time from the system clock. - * On success, set *t and *info (if not NULL), and return 0. - * On error, raise an exception and return -1. - */ -PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - If the internal clock fails, silently ignore the error and return 0. - On integer overflow, silently ignore the overflow and clamp the clock to - [_PyTime_MIN; _PyTime_MAX]. - - Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void); - -/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. - The clock is not affected by system clock updates. The reference point of - the returned value is undefined, so that only the difference between the - results of consecutive calls is valid. - - Fill info (if set) with information of the function used to get the time. - - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - - -/* Converts a timestamp to the Gregorian time, using the local time zone. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm); - -/* Converts a timestamp to the Gregorian time, assuming UTC. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm); - -/* Get the performance counter: clock with the highest available resolution to - measure a short duration. - - If the internal clock fails, silently ignore the error and return 0. - On integer overflow, silently ignore the overflow and clamp the clock to - [_PyTime_MIN; _PyTime_MAX]. - - Use _PyTime_GetPerfCounterWithInfo() to check for failure. */ -PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void); - -/* Get the performance counter: clock with the highest available resolution to - measure a short duration. - - Fill info (if set) with information of the function used to get the time. - - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo( - _PyTime_t *t, - _Py_clock_info_t *info); - - -// Create a deadline. -// Pseudo code: _PyTime_GetMonotonicClock() + timeout. -PyAPI_FUNC(_PyTime_t) _PyDeadline_Init(_PyTime_t timeout); - -// Get remaining time from a deadline. -// Pseudo code: deadline - _PyTime_GetMonotonicClock(). -PyAPI_FUNC(_PyTime_t) _PyDeadline_Get(_PyTime_t deadline); - -#ifdef __cplusplus -} -#endif - -#endif /* Py_PYTIME_H */ -#endif /* Py_LIMITED_API */ diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 0a9f24efbdb908..ee93f7d99d9155 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include "pycore_time.h" // _PyTime_t + struct _import_runtime_state { /* The builtin modules (defined in config.c). */ diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h index 949170c4493799..3d394e8d36a132 100644 --- a/Include/internal/pycore_time.h +++ b/Include/internal/pycore_time.h @@ -1,3 +1,46 @@ +// The _PyTime_t API is written to use timestamp and timeout values stored in +// various formats and to read clocks. +// +// The _PyTime_t type is an integer to support directly common arithmetic +// operations like t1 + t2. +// +// The _PyTime_t API supports a resolution of 1 nanosecond. The _PyTime_t type +// is signed to support negative timestamps. The supported range is around +// [-292.3 years; +292.3 years]. Using the Unix epoch (January 1st, 1970), the +// supported date range is around [1677-09-21; 2262-04-11]. +// +// Formats: +// +// * seconds +// * seconds as a floating pointer number (C double) +// * milliseconds (10^-3 seconds) +// * microseconds (10^-6 seconds) +// * 100 nanoseconds (10^-7 seconds) +// * nanoseconds (10^-9 seconds) +// * timeval structure, 1 microsecond resolution (10^-6 seconds) +// * timespec structure, 1 nanosecond resolution (10^-9 seconds) +// +// Integer overflows are detected and raise OverflowError. Conversion to a +// resolution worse than 1 nanosecond is rounded correctly with the requested +// rounding mode. There are 4 rounding modes: floor (towards -inf), ceiling +// (towards +inf), half even and up (away from zero). +// +// Some functions clamp the result in the range [_PyTime_MIN; _PyTime_MAX], so +// the caller doesn't have to handle errors and doesn't need to hold the GIL. +// For example, _PyTime_Add(t1, t2) computes t1+t2 and clamp the result on +// overflow. +// +// Clocks: +// +// * System clock +// * Monotonic clock +// * Performance counter +// +// Operations like (t * k / q) with integers are implemented in a way to reduce +// the risk of integer overflow. Such operation is used to convert a clock +// value expressed in ticks with a frequency to _PyTime_t, like +// QueryPerformanceCounter() with QueryPerformanceFrequency(). + #ifndef Py_INTERNAL_TIME_H #define Py_INTERNAL_TIME_H #ifdef __cplusplus @@ -19,6 +62,275 @@ struct _time_runtime_state { }; +#ifdef __clang__ +struct timeval; +#endif + +/* _PyTime_t: Python timestamp with subsecond precision. It can be used to + store a duration, and so indirectly a date (related to another date, like + UNIX epoch). */ +typedef int64_t _PyTime_t; +// _PyTime_MIN nanoseconds is around -292.3 years +#define _PyTime_MIN INT64_MIN +// _PyTime_MAX nanoseconds is around +292.3 years +#define _PyTime_MAX INT64_MAX +#define _SIZEOF_PYTIME_T 8 + +typedef enum { + /* Round towards minus infinity (-inf). + For example, used to read a clock. */ + _PyTime_ROUND_FLOOR=0, + /* Round towards infinity (+inf). + For example, used for timeout to wait "at least" N seconds. */ + _PyTime_ROUND_CEILING=1, + /* Round to nearest with ties going to nearest even integer. + For example, used to round from a Python float. */ + _PyTime_ROUND_HALF_EVEN=2, + /* Round away from zero + For example, used for timeout. _PyTime_ROUND_CEILING rounds + -1e-9 to 0 milliseconds which causes bpo-31786 issue. + _PyTime_ROUND_UP rounds -1e-9 to -1 millisecond which keeps + the timeout sign as expected. select.poll(timeout) must block + for negative values." */ + _PyTime_ROUND_UP=3, + /* _PyTime_ROUND_TIMEOUT (an alias for _PyTime_ROUND_UP) should be + used for timeouts. */ + _PyTime_ROUND_TIMEOUT = _PyTime_ROUND_UP +} _PyTime_round_t; + + +/* Convert a time_t to a PyLong. */ +PyAPI_FUNC(PyObject*) _PyLong_FromTime_t(time_t sec); + +/* Convert a PyLong to a time_t. */ +PyAPI_FUNC(time_t) _PyLong_AsTime_t(PyObject *obj); + +/* Convert a number of seconds, int or float, to time_t. */ +PyAPI_FUNC(int) _PyTime_ObjectToTime_t( + PyObject *obj, + time_t *sec, + _PyTime_round_t); + +/* Convert a number of seconds, int or float, to a timeval structure. + usec is in the range [0; 999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimeval( + PyObject *obj, + time_t *sec, + long *usec, + _PyTime_round_t); + +/* Convert a number of seconds, int or float, to a timespec structure. + nsec is in the range [0; 999999999] and rounded towards zero. + For example, -1.2 is converted to (-2, 800000000). */ +PyAPI_FUNC(int) _PyTime_ObjectToTimespec( + PyObject *obj, + time_t *sec, + long *nsec, + _PyTime_round_t); + + +/* Create a timestamp from a number of seconds. */ +PyAPI_FUNC(_PyTime_t) _PyTime_FromSeconds(int seconds); + +/* Macro to create a timestamp from a number of seconds, no integer overflow. + Only use the macro for small values, prefer _PyTime_FromSeconds(). */ +#define _PYTIME_FROMSECONDS(seconds) \ + ((_PyTime_t)(seconds) * (1000 * 1000 * 1000)) + +/* Create a timestamp from a number of nanoseconds. */ +PyAPI_FUNC(_PyTime_t) _PyTime_FromNanoseconds(_PyTime_t ns); + +/* Create a timestamp from a number of microseconds. + * Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. */ +extern _PyTime_t _PyTime_FromMicrosecondsClamp(_PyTime_t us); + +/* Create a timestamp from nanoseconds (Python int). */ +PyAPI_FUNC(int) _PyTime_FromNanosecondsObject(_PyTime_t *t, + PyObject *obj); + +/* Convert a number of seconds (Python float or int) to a timestamp. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_FromSecondsObject(_PyTime_t *t, + PyObject *obj, + _PyTime_round_t round); + +/* Convert a number of milliseconds (Python float or int, 10^-3) to a timestamp. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_FromMillisecondsObject(_PyTime_t *t, + PyObject *obj, + _PyTime_round_t round); + +/* Convert a timestamp to a number of seconds as a C double. */ +PyAPI_FUNC(double) _PyTime_AsSecondsDouble(_PyTime_t t); + +/* Convert timestamp to a number of milliseconds (10^-3 seconds). */ +PyAPI_FUNC(_PyTime_t) _PyTime_AsMilliseconds(_PyTime_t t, + _PyTime_round_t round); + +/* Convert timestamp to a number of microseconds (10^-6 seconds). */ +PyAPI_FUNC(_PyTime_t) _PyTime_AsMicroseconds(_PyTime_t t, + _PyTime_round_t round); + +/* Convert timestamp to a number of nanoseconds (10^-9 seconds). */ +PyAPI_FUNC(_PyTime_t) _PyTime_AsNanoseconds(_PyTime_t t); + +#ifdef MS_WINDOWS +// Convert timestamp to a number of 100 nanoseconds (10^-7 seconds). +extern _PyTime_t _PyTime_As100Nanoseconds(_PyTime_t t, + _PyTime_round_t round); +#endif + +/* Convert timestamp to a number of nanoseconds (10^-9 seconds) as a Python int + object. */ +PyAPI_FUNC(PyObject*) _PyTime_AsNanosecondsObject(_PyTime_t t); + +#ifndef MS_WINDOWS +/* Create a timestamp from a timeval structure. + Raise an exception and return -1 on overflow, return 0 on success. */ +extern int _PyTime_FromTimeval(_PyTime_t *tp, struct timeval *tv); +#endif + +/* Convert a timestamp to a timeval structure (microsecond resolution). + tv_usec is always positive. + Raise an exception and return -1 if the conversion overflowed, + return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimeval(_PyTime_t t, + struct timeval *tv, + _PyTime_round_t round); + +/* Similar to _PyTime_AsTimeval() but don't raise an exception on overflow. + On overflow, clamp tv_sec to _PyTime_t min/max. */ +PyAPI_FUNC(void) _PyTime_AsTimeval_clamp(_PyTime_t t, + struct timeval *tv, + _PyTime_round_t round); + +/* Convert a timestamp to a number of seconds (secs) and microseconds (us). + us is always positive. This function is similar to _PyTime_AsTimeval() + except that secs is always a time_t type, whereas the timeval structure + uses a C long for tv_sec on Windows. + Raise an exception and return -1 if the conversion overflowed, + return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimevalTime_t( + _PyTime_t t, + time_t *secs, + int *us, + _PyTime_round_t round); + +#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_KQUEUE) +/* Create a timestamp from a timespec structure. + Raise an exception and return -1 on overflow, return 0 on success. */ +extern int _PyTime_FromTimespec(_PyTime_t *tp, struct timespec *ts); + +/* Convert a timestamp to a timespec structure (nanosecond resolution). + tv_nsec is always positive. + Raise an exception and return -1 on error, return 0 on success. */ +PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts); + +/* Similar to _PyTime_AsTimespec() but don't raise an exception on overflow. + On overflow, clamp tv_sec to _PyTime_t min/max. */ +PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts); +#endif + + +// Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. +extern _PyTime_t _PyTime_Add(_PyTime_t t1, _PyTime_t t2); + +/* Compute ticks * mul / div. + Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. + The caller must ensure that ((div - 1) * mul) cannot overflow. */ +extern _PyTime_t _PyTime_MulDiv(_PyTime_t ticks, + _PyTime_t mul, + _PyTime_t div); + +/* Structure used by time.get_clock_info() */ +typedef struct { + const char *implementation; + int monotonic; + int adjustable; + double resolution; +} _Py_clock_info_t; + +/* Get the current time from the system clock. + + If the internal clock fails, silently ignore the error and return 0. + On integer overflow, silently ignore the overflow and clamp the clock to + [_PyTime_MIN; _PyTime_MAX]. + + Use _PyTime_GetSystemClockWithInfo() to check for failure. */ +PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void); + +/* Get the current time from the system clock. + * On success, set *t and *info (if not NULL), and return 0. + * On error, raise an exception and return -1. + */ +PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); + +/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. + The clock is not affected by system clock updates. The reference point of + the returned value is undefined, so that only the difference between the + results of consecutive calls is valid. + + If the internal clock fails, silently ignore the error and return 0. + On integer overflow, silently ignore the overflow and clamp the clock to + [_PyTime_MIN; _PyTime_MAX]. + + Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */ +PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void); + +/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards. + The clock is not affected by system clock updates. The reference point of + the returned value is undefined, so that only the difference between the + results of consecutive calls is valid. + + Fill info (if set) with information of the function used to get the time. + + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); + + +/* Converts a timestamp to the Gregorian time, using the local time zone. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm); + +/* Converts a timestamp to the Gregorian time, assuming UTC. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm); + +/* Get the performance counter: clock with the highest available resolution to + measure a short duration. + + If the internal clock fails, silently ignore the error and return 0. + On integer overflow, silently ignore the overflow and clamp the clock to + [_PyTime_MIN; _PyTime_MAX]. + + Use _PyTime_GetPerfCounterWithInfo() to check for failure. */ +PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void); + +/* Get the performance counter: clock with the highest available resolution to + measure a short duration. + + Fill info (if set) with information of the function used to get the time. + + Return 0 on success, raise an exception and return -1 on error. */ +extern int _PyTime_GetPerfCounterWithInfo( + _PyTime_t *t, + _Py_clock_info_t *info); + + +// Create a deadline. +// Pseudo code: _PyTime_GetMonotonicClock() + timeout. +PyAPI_FUNC(_PyTime_t) _PyDeadline_Init(_PyTime_t timeout); + +// Get remaining time from a deadline. +// Pseudo code: deadline - _PyTime_GetMonotonicClock(). +PyAPI_FUNC(_PyTime_t) _PyDeadline_Get(_PyTime_t deadline); + + #ifdef __cplusplus } #endif diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 02cc3f43a66a67..3b5640abdb6b89 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -14,6 +14,10 @@ import _testcapi except ImportError: _testcapi = None +try: + import _testinternalcapi +except ImportError: + _testinternalcapi = None from test.support import skip_if_buggy_ucrt_strfptime @@ -761,7 +765,8 @@ def test_short_times(self): self.assertIs(lt.tm_zone, None) -@unittest.skipIf(_testcapi is None, 'need the _testcapi module') +@unittest.skipIf(_testcapi is None, 'need the _testinternalcapi module') +@unittest.skipIf(_testinternalcapi is None, 'need the _testinternalcapi module') class CPyTimeTestCase: """ Base class to test the C _PyTime_t API. @@ -769,7 +774,7 @@ class CPyTimeTestCase: OVERFLOW_SECONDS = None def setUp(self): - from _testcapi import SIZEOF_TIME_T + from _testinternalcapi import SIZEOF_TIME_T bits = SIZEOF_TIME_T * 8 - 1 self.time_t_min = -2 ** bits self.time_t_max = 2 ** bits - 1 @@ -897,39 +902,39 @@ class TestCPyTime(CPyTimeTestCase, unittest.TestCase): OVERFLOW_SECONDS = math.ceil((2**63 + 1) / SEC_TO_NS) def test_FromSeconds(self): - from _testcapi import PyTime_FromSeconds + from _testinternalcapi import _PyTime_FromSeconds - # PyTime_FromSeconds() expects a C int, reject values out of range + # _PyTime_FromSeconds() expects a C int, reject values out of range def c_int_filter(secs): return (_testcapi.INT_MIN <= secs <= _testcapi.INT_MAX) - self.check_int_rounding(lambda secs, rnd: PyTime_FromSeconds(secs), + self.check_int_rounding(lambda secs, rnd: _PyTime_FromSeconds(secs), lambda secs: secs * SEC_TO_NS, value_filter=c_int_filter) # test nan for time_rnd, _ in ROUNDING_MODES: with self.assertRaises(TypeError): - PyTime_FromSeconds(float('nan')) + _PyTime_FromSeconds(float('nan')) def test_FromSecondsObject(self): - from _testcapi import PyTime_FromSecondsObject + from _testinternalcapi import _PyTime_FromSecondsObject self.check_int_rounding( - PyTime_FromSecondsObject, + _PyTime_FromSecondsObject, lambda secs: secs * SEC_TO_NS) self.check_float_rounding( - PyTime_FromSecondsObject, + _PyTime_FromSecondsObject, lambda ns: self.decimal_round(ns * SEC_TO_NS)) # test nan for time_rnd, _ in ROUNDING_MODES: with self.assertRaises(ValueError): - PyTime_FromSecondsObject(float('nan'), time_rnd) + _PyTime_FromSecondsObject(float('nan'), time_rnd) def test_AsSecondsDouble(self): - from _testcapi import PyTime_AsSecondsDouble + from _testinternalcapi import _PyTime_AsSecondsDouble def float_converter(ns): if abs(ns) % SEC_TO_NS == 0: @@ -937,14 +942,14 @@ def float_converter(ns): else: return float(ns) / SEC_TO_NS - self.check_int_rounding(lambda ns, rnd: PyTime_AsSecondsDouble(ns), + self.check_int_rounding(lambda ns, rnd: _PyTime_AsSecondsDouble(ns), float_converter, NS_TO_SEC) # test nan for time_rnd, _ in ROUNDING_MODES: with self.assertRaises(TypeError): - PyTime_AsSecondsDouble(float('nan')) + _PyTime_AsSecondsDouble(float('nan')) def create_decimal_converter(self, denominator): denom = decimal.Decimal(denominator) @@ -956,7 +961,7 @@ def converter(value): return converter def test_AsTimeval(self): - from _testcapi import PyTime_AsTimeval + from _testinternalcapi import _PyTime_AsTimeval us_converter = self.create_decimal_converter(US_TO_NS) @@ -973,28 +978,28 @@ def seconds_filter(secs): else: seconds_filter = self.time_t_filter - self.check_int_rounding(PyTime_AsTimeval, + self.check_int_rounding(_PyTime_AsTimeval, timeval_converter, NS_TO_SEC, value_filter=seconds_filter) - @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'), - 'need _testcapi.PyTime_AsTimespec') + @unittest.skipUnless(hasattr(_testinternalcapi, '_PyTime_AsTimespec'), + 'need _testinternalcapi._PyTime_AsTimespec') def test_AsTimespec(self): - from _testcapi import PyTime_AsTimespec + from _testinternalcapi import _PyTime_AsTimespec def timespec_converter(ns): return divmod(ns, SEC_TO_NS) - self.check_int_rounding(lambda ns, rnd: PyTime_AsTimespec(ns), + self.check_int_rounding(lambda ns, rnd: _PyTime_AsTimespec(ns), timespec_converter, NS_TO_SEC, value_filter=self.time_t_filter) - @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimeval_clamp'), - 'need _testcapi.PyTime_AsTimeval_clamp') + @unittest.skipUnless(hasattr(_testinternalcapi, '_PyTime_AsTimeval_clamp'), + 'need _testinternalcapi._PyTime_AsTimeval_clamp') def test_AsTimeval_clamp(self): - from _testcapi import PyTime_AsTimeval_clamp + from _testinternalcapi import _PyTime_AsTimeval_clamp if sys.platform == 'win32': from _testcapi import LONG_MIN, LONG_MAX @@ -1005,7 +1010,7 @@ def test_AsTimeval_clamp(self): tv_sec_min = self.time_t_min for t in (_PyTime_MIN, _PyTime_MAX): - ts = PyTime_AsTimeval_clamp(t, _PyTime.ROUND_CEILING) + ts = _PyTime_AsTimeval_clamp(t, _PyTime.ROUND_CEILING) with decimal.localcontext() as context: context.rounding = decimal.ROUND_CEILING us = self.decimal_round(decimal.Decimal(t) / US_TO_NS) @@ -1018,13 +1023,13 @@ def test_AsTimeval_clamp(self): tv_usec = 0 self.assertEqual(ts, (tv_sec, tv_usec)) - @unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec_clamp'), - 'need _testcapi.PyTime_AsTimespec_clamp') + @unittest.skipUnless(hasattr(_testinternalcapi, '_PyTime_AsTimespec_clamp'), + 'need _testinternalcapi._PyTime_AsTimespec_clamp') def test_AsTimespec_clamp(self): - from _testcapi import PyTime_AsTimespec_clamp + from _testinternalcapi import _PyTime_AsTimespec_clamp for t in (_PyTime_MIN, _PyTime_MAX): - ts = PyTime_AsTimespec_clamp(t) + ts = _PyTime_AsTimespec_clamp(t) tv_sec, tv_nsec = divmod(t, NS_TO_SEC) if self.time_t_max < tv_sec: tv_sec = self.time_t_max @@ -1035,16 +1040,16 @@ def test_AsTimespec_clamp(self): self.assertEqual(ts, (tv_sec, tv_nsec)) def test_AsMilliseconds(self): - from _testcapi import PyTime_AsMilliseconds + from _testinternalcapi import _PyTime_AsMilliseconds - self.check_int_rounding(PyTime_AsMilliseconds, + self.check_int_rounding(_PyTime_AsMilliseconds, self.create_decimal_converter(MS_TO_NS), NS_TO_SEC) def test_AsMicroseconds(self): - from _testcapi import PyTime_AsMicroseconds + from _testinternalcapi import _PyTime_AsMicroseconds - self.check_int_rounding(PyTime_AsMicroseconds, + self.check_int_rounding(_PyTime_AsMicroseconds, self.create_decimal_converter(US_TO_NS), NS_TO_SEC) @@ -1058,13 +1063,13 @@ class TestOldPyTime(CPyTimeTestCase, unittest.TestCase): OVERFLOW_SECONDS = 2 ** 64 def test_object_to_time_t(self): - from _testcapi import pytime_object_to_time_t + from _testinternalcapi import _PyTime_ObjectToTime_t - self.check_int_rounding(pytime_object_to_time_t, + self.check_int_rounding(_PyTime_ObjectToTime_t, lambda secs: secs, value_filter=self.time_t_filter) - self.check_float_rounding(pytime_object_to_time_t, + self.check_float_rounding(_PyTime_ObjectToTime_t, self.decimal_round, value_filter=self.time_t_filter) @@ -1084,36 +1089,36 @@ def converter(secs): return converter def test_object_to_timeval(self): - from _testcapi import pytime_object_to_timeval + from _testinternalcapi import _PyTime_ObjectToTimeval - self.check_int_rounding(pytime_object_to_timeval, + self.check_int_rounding(_PyTime_ObjectToTimeval, lambda secs: (secs, 0), value_filter=self.time_t_filter) - self.check_float_rounding(pytime_object_to_timeval, + self.check_float_rounding(_PyTime_ObjectToTimeval, self.create_converter(SEC_TO_US), value_filter=self.time_t_filter) # test nan for time_rnd, _ in ROUNDING_MODES: with self.assertRaises(ValueError): - pytime_object_to_timeval(float('nan'), time_rnd) + _PyTime_ObjectToTimeval(float('nan'), time_rnd) def test_object_to_timespec(self): - from _testcapi import pytime_object_to_timespec + from _testinternalcapi import _PyTime_ObjectToTimespec - self.check_int_rounding(pytime_object_to_timespec, + self.check_int_rounding(_PyTime_ObjectToTimespec, lambda secs: (secs, 0), value_filter=self.time_t_filter) - self.check_float_rounding(pytime_object_to_timespec, + self.check_float_rounding(_PyTime_ObjectToTimespec, self.create_converter(SEC_TO_NS), value_filter=self.time_t_filter) # test nan for time_rnd, _ in ROUNDING_MODES: with self.assertRaises(ValueError): - pytime_object_to_timespec(float('nan'), time_rnd) + _PyTime_ObjectToTimespec(float('nan'), time_rnd) @unittest.skipUnless(sys.platform == "darwin", "test weak linking on macOS") class TestTimeWeaklinking(unittest.TestCase): diff --git a/Makefile.pre.in b/Makefile.pre.in index c1b512b94765de..54d0516ad4423b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1710,7 +1710,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/pystate.h \ $(srcdir)/Include/cpython/pythonrun.h \ $(srcdir)/Include/cpython/pythread.h \ - $(srcdir)/Include/cpython/pytime.h \ $(srcdir)/Include/cpython/setobject.h \ $(srcdir)/Include/cpython/sysmodule.h \ $(srcdir)/Include/cpython/traceback.h \ diff --git a/Misc/NEWS.d/next/C API/2023-07-01-21-23-33.gh-issue-106316.hp2Ijw.rst b/Misc/NEWS.d/next/C API/2023-07-01-21-23-33.gh-issue-106316.hp2Ijw.rst new file mode 100644 index 00000000000000..733954eb8614f2 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-01-21-23-33.gh-issue-106316.hp2Ijw.rst @@ -0,0 +1,2 @@ +Remove ``cpython/pytime.h`` header file: it only contained private +functions. Patch by Victor Stinner. diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index c228cd5642e75b..11a022e3d2044e 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -159,7 +159,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index db5be842b8a35c..69cc05135c2a72 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_time.h" // _PyTime_t #include "structmember.h" // PyMemberDef #include // offsetof() diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index d1991ac6b464f2..aaec0a61916948 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -28,7 +28,6 @@ int _PyTestCapi_Init_Vectorcall(PyObject *module); int _PyTestCapi_Init_Heaptype(PyObject *module); int _PyTestCapi_Init_Unicode(PyObject *module); int _PyTestCapi_Init_GetArgs(PyObject *module); -int _PyTestCapi_Init_PyTime(PyObject *module); int _PyTestCapi_Init_DateTime(PyObject *module); int _PyTestCapi_Init_Docstring(PyObject *module); int _PyTestCapi_Init_Mem(PyObject *module); diff --git a/Modules/_testcapi/pytime.c b/Modules/_testcapi/pytime.c index 7422bafc30193a..e69de29bb2d1d6 100644 --- a/Modules/_testcapi/pytime.c +++ b/Modules/_testcapi/pytime.c @@ -1,274 +0,0 @@ -#include "parts.h" - -#ifdef MS_WINDOWS -# include // struct timeval -#endif - -static PyObject * -test_pytime_fromseconds(PyObject *self, PyObject *args) -{ - int seconds; - if (!PyArg_ParseTuple(args, "i", &seconds)) { - return NULL; - } - _PyTime_t ts = _PyTime_FromSeconds(seconds); - return _PyTime_AsNanosecondsObject(ts); -} - -static int -check_time_rounding(int round) -{ - if (round != _PyTime_ROUND_FLOOR - && round != _PyTime_ROUND_CEILING - && round != _PyTime_ROUND_HALF_EVEN - && round != _PyTime_ROUND_UP) - { - PyErr_SetString(PyExc_ValueError, "invalid rounding"); - return -1; - } - return 0; -} - -static PyObject * -test_pytime_fromsecondsobject(PyObject *self, PyObject *args) -{ - PyObject *obj; - int round; - if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - _PyTime_t ts; - if (_PyTime_FromSecondsObject(&ts, obj, round) == -1) { - return NULL; - } - return _PyTime_AsNanosecondsObject(ts); -} - -static PyObject * -test_pytime_assecondsdouble(PyObject *self, PyObject *args) -{ - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - _PyTime_t ts; - if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) { - return NULL; - } - double d = _PyTime_AsSecondsDouble(ts); - return PyFloat_FromDouble(d); -} - -static PyObject * -test_PyTime_AsTimeval(PyObject *self, PyObject *args) -{ - PyObject *obj; - int round; - if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - struct timeval tv; - if (_PyTime_AsTimeval(t, &tv, round) < 0) { - return NULL; - } - - PyObject *seconds = PyLong_FromLongLong(tv.tv_sec); - if (seconds == NULL) { - return NULL; - } - return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); -} - -static PyObject * -test_PyTime_AsTimeval_clamp(PyObject *self, PyObject *args) -{ - PyObject *obj; - int round; - if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - struct timeval tv; - _PyTime_AsTimeval_clamp(t, &tv, round); - - PyObject *seconds = PyLong_FromLongLong(tv.tv_sec); - if (seconds == NULL) { - return NULL; - } - return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); -} - -#ifdef HAVE_CLOCK_GETTIME -static PyObject * -test_PyTime_AsTimespec(PyObject *self, PyObject *args) -{ - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - struct timespec ts; - if (_PyTime_AsTimespec(t, &ts) == -1) { - return NULL; - } - return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); -} - -static PyObject * -test_PyTime_AsTimespec_clamp(PyObject *self, PyObject *args) -{ - PyObject *obj; - if (!PyArg_ParseTuple(args, "O", &obj)) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - struct timespec ts; - _PyTime_AsTimespec_clamp(t, &ts); - return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); -} -#endif - -static PyObject * -test_PyTime_AsMilliseconds(PyObject *self, PyObject *args) -{ - PyObject *obj; - int round; - if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - _PyTime_t ms = _PyTime_AsMilliseconds(t, round); - _PyTime_t ns = _PyTime_FromNanoseconds(ms); - return _PyTime_AsNanosecondsObject(ns); -} - -static PyObject * -test_PyTime_AsMicroseconds(PyObject *self, PyObject *args) -{ - PyObject *obj; - int round; - if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { - return NULL; - } - _PyTime_t t; - if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - _PyTime_t us = _PyTime_AsMicroseconds(t, round); - _PyTime_t ns = _PyTime_FromNanoseconds(us); - return _PyTime_AsNanosecondsObject(ns); -} - -static PyObject * -test_pytime_object_to_time_t(PyObject *self, PyObject *args) -{ - PyObject *obj; - time_t sec; - int round; - if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_time_t", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - if (_PyTime_ObjectToTime_t(obj, &sec, round) == -1) { - return NULL; - } - return _PyLong_FromTime_t(sec); -} - -static PyObject * -test_pytime_object_to_timeval(PyObject *self, PyObject *args) -{ - PyObject *obj; - time_t sec; - long usec; - int round; - if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_timeval", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - if (_PyTime_ObjectToTimeval(obj, &sec, &usec, round) == -1) { - return NULL; - } - return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), usec); -} - -static PyObject * -test_pytime_object_to_timespec(PyObject *self, PyObject *args) -{ - PyObject *obj; - time_t sec; - long nsec; - int round; - if (!PyArg_ParseTuple(args, "Oi:pytime_object_to_timespec", &obj, &round)) { - return NULL; - } - if (check_time_rounding(round) < 0) { - return NULL; - } - if (_PyTime_ObjectToTimespec(obj, &sec, &nsec, round) == -1) { - return NULL; - } - return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); -} - -static PyMethodDef test_methods[] = { - {"PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS}, - {"PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS}, - {"PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS}, -#ifdef HAVE_CLOCK_GETTIME - {"PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS}, - {"PyTime_AsTimespec_clamp", test_PyTime_AsTimespec_clamp, METH_VARARGS}, -#endif - {"PyTime_AsTimeval", test_PyTime_AsTimeval, METH_VARARGS}, - {"PyTime_AsTimeval_clamp", test_PyTime_AsTimeval_clamp, METH_VARARGS}, - {"PyTime_FromSeconds", test_pytime_fromseconds, METH_VARARGS}, - {"PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS}, - {"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS}, - {"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS}, - {"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS}, - {NULL}, -}; - -int -_PyTestCapi_Init_PyTime(PyObject *mod) -{ - if (PyModule_AddFunctions(mod, test_methods) < 0) { - return -1; - } - return 0; -} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index dc8acec6c76921..ec2e64f2f46fc1 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4216,9 +4216,6 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_GetArgs(m) < 0) { return NULL; } - if (_PyTestCapi_Init_PyTime(m) < 0) { - return NULL; - } if (_PyTestCapi_Init_DateTime(m) < 0) { return NULL; } diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 3c0c2adaf6f843..c598d7edef8ae2 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -31,6 +31,10 @@ #include "clinic/_testinternalcapi.c.h" +#ifdef MS_WINDOWS +# include // struct timeval +#endif + #define MODULE_NAME "_testinternalcapi" @@ -969,6 +973,249 @@ pending_identify(PyObject *self, PyObject *args) } +static PyObject * +test_pytime_fromseconds(PyObject *self, PyObject *args) +{ + int seconds; + if (!PyArg_ParseTuple(args, "i", &seconds)) { + return NULL; + } + _PyTime_t ts = _PyTime_FromSeconds(seconds); + return _PyTime_AsNanosecondsObject(ts); +} + +static int +check_time_rounding(int round) +{ + if (round != _PyTime_ROUND_FLOOR + && round != _PyTime_ROUND_CEILING + && round != _PyTime_ROUND_HALF_EVEN + && round != _PyTime_ROUND_UP) + { + PyErr_SetString(PyExc_ValueError, "invalid rounding"); + return -1; + } + return 0; +} + +static PyObject * +test_pytime_fromsecondsobject(PyObject *self, PyObject *args) +{ + PyObject *obj; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + _PyTime_t ts; + if (_PyTime_FromSecondsObject(&ts, obj, round) == -1) { + return NULL; + } + return _PyTime_AsNanosecondsObject(ts); +} + +static PyObject * +test_pytime_assecondsdouble(PyObject *self, PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return NULL; + } + _PyTime_t ts; + if (_PyTime_FromNanosecondsObject(&ts, obj) < 0) { + return NULL; + } + double d = _PyTime_AsSecondsDouble(ts); + return PyFloat_FromDouble(d); +} + +static PyObject * +test_PyTime_AsTimeval(PyObject *self, PyObject *args) +{ + PyObject *obj; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + struct timeval tv; + if (_PyTime_AsTimeval(t, &tv, round) < 0) { + return NULL; + } + + PyObject *seconds = PyLong_FromLongLong(tv.tv_sec); + if (seconds == NULL) { + return NULL; + } + return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); +} + +static PyObject * +test_PyTime_AsTimeval_clamp(PyObject *self, PyObject *args) +{ + PyObject *obj; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + struct timeval tv; + _PyTime_AsTimeval_clamp(t, &tv, round); + + PyObject *seconds = PyLong_FromLongLong(tv.tv_sec); + if (seconds == NULL) { + return NULL; + } + return Py_BuildValue("Nl", seconds, (long)tv.tv_usec); +} + +#ifdef HAVE_CLOCK_GETTIME +static PyObject * +test_PyTime_AsTimespec(PyObject *self, PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + struct timespec ts; + if (_PyTime_AsTimespec(t, &ts) == -1) { + return NULL; + } + return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); +} + +static PyObject * +test_PyTime_AsTimespec_clamp(PyObject *self, PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + struct timespec ts; + _PyTime_AsTimespec_clamp(t, &ts); + return Py_BuildValue("Nl", _PyLong_FromTime_t(ts.tv_sec), ts.tv_nsec); +} +#endif + +static PyObject * +test_PyTime_AsMilliseconds(PyObject *self, PyObject *args) +{ + PyObject *obj; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + _PyTime_t ms = _PyTime_AsMilliseconds(t, round); + _PyTime_t ns = _PyTime_FromNanoseconds(ms); + return _PyTime_AsNanosecondsObject(ns); +} + +static PyObject * +test_PyTime_AsMicroseconds(PyObject *self, PyObject *args) +{ + PyObject *obj; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + _PyTime_t t; + if (_PyTime_FromNanosecondsObject(&t, obj) < 0) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + _PyTime_t us = _PyTime_AsMicroseconds(t, round); + _PyTime_t ns = _PyTime_FromNanoseconds(us); + return _PyTime_AsNanosecondsObject(ns); +} + +static PyObject * +test_pytime_object_to_time_t(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + if (_PyTime_ObjectToTime_t(obj, &sec, round) == -1) { + return NULL; + } + return _PyLong_FromTime_t(sec); +} + +static PyObject * +test_pytime_object_to_timeval(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long usec; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + if (_PyTime_ObjectToTimeval(obj, &sec, &usec, round) == -1) { + return NULL; + } + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), usec); +} + +static PyObject * +test_pytime_object_to_timespec(PyObject *self, PyObject *args) +{ + PyObject *obj; + time_t sec; + long nsec; + int round; + if (!PyArg_ParseTuple(args, "Oi", &obj, &round)) { + return NULL; + } + if (check_time_rounding(round) < 0) { + return NULL; + } + if (_PyTime_ObjectToTimespec(obj, &sec, &nsec, round) == -1) { + return NULL; + } + return Py_BuildValue("Nl", _PyLong_FromTime_t(sec), nsec); +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1005,6 +1252,20 @@ static PyMethodDef module_functions[] = { METH_VARARGS | METH_KEYWORDS}, // {"pending_fd_identify", pending_fd_identify, METH_VARARGS, NULL}, {"pending_identify", pending_identify, METH_VARARGS, NULL}, + {"_PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS}, + {"_PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS}, + {"_PyTime_AsSecondsDouble", test_pytime_assecondsdouble, METH_VARARGS}, +#ifdef HAVE_CLOCK_GETTIME + {"_PyTime_AsTimespec", test_PyTime_AsTimespec, METH_VARARGS}, + {"_PyTime_AsTimespec_clamp", test_PyTime_AsTimespec_clamp, METH_VARARGS}, +#endif + {"_PyTime_AsTimeval", test_PyTime_AsTimeval, METH_VARARGS}, + {"_PyTime_AsTimeval_clamp", test_PyTime_AsTimeval_clamp, METH_VARARGS}, + {"_PyTime_FromSeconds", test_pytime_fromseconds, METH_VARARGS}, + {"_PyTime_FromSecondsObject", test_pytime_fromsecondsobject, METH_VARARGS}, + {"_PyTime_ObjectToTime_t", test_pytime_object_to_time_t, METH_VARARGS}, + {"_PyTime_ObjectToTimespec", test_pytime_object_to_timespec, METH_VARARGS}, + {"_PyTime_ObjectToTimeval", test_pytime_object_to_timeval, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; @@ -1019,6 +1280,11 @@ module_exec(PyObject *module) return 1; } + if (PyModule_AddObject(module, "SIZEOF_TIME_T", + PyLong_FromSsize_t(sizeof(time_t))) < 0) { + return 1; + } + return 0; } diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index dca7abff89146e..922b41005e8419 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -8,6 +8,7 @@ //#include #include "Python.h" #include "pycore_namespace.h" // _PyNamespace_New() +#include "pycore_time.h" // _PyTime_t typedef struct { diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 9a4943c9eb2f75..7ab0804ad27233 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -14,6 +14,7 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_set_inheritable() +#include "pycore_time.h" // _PyTime_t #include "structmember.h" // PyMemberDef #ifdef HAVE_SYS_DEVPOLL_H diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index f5ca00450ee92a..663ae3d6e0dd6c 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -1,5 +1,7 @@ /* Socket module header file */ +#include "pycore_time.h" // _PyTime_t + /* Includes needed for the sockaddr_* symbols below */ #ifndef MS_WINDOWS #ifdef __VMS diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 3db9426d1a25ff..de17d74c52e56f 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -100,7 +100,6 @@ - @@ -131,4 +130,4 @@ - \ No newline at end of file + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index 8df4874659fa1c..637f7178d39d0e 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -30,9 +30,6 @@ Source Files - - Source Files - Source Files @@ -75,4 +72,4 @@ Resource Files - \ No newline at end of file + diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index c99bc905c89e21..58abd871376a06 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -176,7 +176,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 53e89457f72a37..4d7b5ccf9a8a9e 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -447,9 +447,6 @@ Include\cpython - - Include\cpython - Include\cpython diff --git a/Python/pytime.c b/Python/pytime.c index d36d4417dabb22..49cd5f4e8ea617 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -1,4 +1,5 @@ #include "Python.h" +#include "pycore_time.h" // _PyTime_t #ifdef MS_WINDOWS # include // struct timeval #endif diff --git a/Tools/build/stable_abi.py b/Tools/build/stable_abi.py index 4cd1cd953d0d29..7cba788ff33578 100644 --- a/Tools/build/stable_abi.py +++ b/Tools/build/stable_abi.py @@ -40,7 +40,6 @@ "longintrepr.h", "parsetok.h", "pyatomic.h", - "pytime.h", "token.h", "ucnhash.h", } diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 147615707a3cb8..0929f7111eac92 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -60,6 +60,13 @@ def preprocess(filename, if not cwd or not os.path.isabs(cwd): cwd = os.path.abspath(cwd or '.') filename = _normpath(filename, cwd) + + postargs = POST_ARGS + if os.path.basename(filename) == 'socketmodule.h': + # Modules/socketmodule.h uses pycore_time.h which needs Py_BUILD_CORE. + # Usually it's defined by the C file which includes it. + postargs += ('-DPy_BUILD_CORE=1',) + text = _common.preprocess( TOOL, filename, @@ -67,7 +74,7 @@ def preprocess(filename, includes=includes, macros=macros, #preargs=PRE_ARGS, - postargs=POST_ARGS, + postargs=postargs, executable=['gcc'], compiler='unix', cwd=cwd, From 0530f4f64629ff97f3feb7524da0833b9535e8b6 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Sun, 2 Jul 2023 01:46:06 +0300 Subject: [PATCH 217/446] gh-102541: Fix Helper.help("mod") for non-existent mod (#105934) If the output arg to Helper() is a stream rather than the default None, which means 'page to stdout', the ImportError from pydoc.resolve is currently not caught in pydoc.doc. The same error is caught when output is None. --------- Co-authored-by: Terry Jan Reedy --- Lib/pydoc.py | 6 +++++- Lib/test/test_pydoc.py | 7 +++++++ .../Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index d69369d4196eaa..185f09e603df2e 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1790,7 +1790,11 @@ def doc(thing, title='Python Library Documentation: %s', forceload=0, raise print(exc) else: - output.write(render_doc(thing, title, forceload, plaintext)) + try: + s = render_doc(thing, title, forceload, plaintext) + except ImportError as exc: + s = str(exc) + output.write(s) def writedoc(thing, forceload=0): """Write HTML documentation to a file in the current directory.""" diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index cefc71cb5a7f54..115ffd3c29d4d6 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -631,6 +631,13 @@ def test_builtin_on_metaclasses(self): # Testing that the subclasses section does not appear self.assertNotIn('Built-in subclasses', text) + def test_fail_help_output_redirect(self): + with StringIO() as buf: + helper = pydoc.Helper(output=buf) + helper.help("abd") + expected = missing_pattern % "abd" + self.assertEqual(expected, buf.getvalue().strip().replace('\n', os.linesep)) + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'trace function introduces __locals__ unexpectedly') @requires_docstrings diff --git a/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst b/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst new file mode 100644 index 00000000000000..efaf5db10f3e1c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-01-16-40-54.gh-issue-102541.C1ahtk.rst @@ -0,0 +1 @@ +Make pydoc.doc catch bad module ImportError when output stream is not None. From 18b1fdebe0cd5e601aa341227c13ec9d89bdf32c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 01:44:07 +0200 Subject: [PATCH 218/446] gh-106320: Remove _PyInterpreterState_Get() alias (#106321) Replace calls to the (removed) slow _PyInterpreterState_Get() with fast inlined _PyInterpreterState_GET() function. --- Doc/whatsnew/3.13.rst | 7 +++++++ Include/cpython/pystate.h | 5 +---- Include/internal/pycore_pystate.h | 2 +- ...3-07-02-00-00-20.gh-issue-106320.tZWcvG.rst | 3 +++ Modules/_threadmodule.c | 2 +- Objects/typeobject.c | 4 ++-- Objects/unicodeobject.c | 2 +- Python/ceval_gil.c | 4 ++-- Python/hamt.c | 2 +- Python/import.c | 2 +- Python/instrumentation.c | 18 +++++++++--------- 11 files changed, 29 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-07-02-00-00-20.gh-issue-106320.tZWcvG.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 628945f7d5804f..8f737c5935f67b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -605,3 +605,10 @@ Removed * Remove ``cpython/pytime.h`` header file: it only contained private functions. (Contributed by Victor Stinner in :gh:`106316`.) + +* Remove ``_PyInterpreterState_Get()`` alias to + :c:func:`PyInterpreterState_Get()` which was kept for backward compatibility + with Python 3.8. The `pythoncapi-compat project + `__ can be used to get + :c:func:`PyInterpreterState_Get()` on Python 3.8 and older. + (Contributed by Victor Stinner in :gh:`106320`.) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index f33c72d4cf4d2a..7d9e41bc2dd7ab 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -261,9 +261,6 @@ struct _ts { /* other API */ -// Alias for backward compatibility with Python 3.8 -#define _PyInterpreterState_Get PyInterpreterState_Get - /* An alias for the internal _PyThreadState_New(), kept for stable ABI compatibility. */ PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); @@ -295,7 +292,7 @@ PyAPI_FUNC(int) PyGILState_Check(void); This function doesn't check for error. Return NULL before _PyGILState_Init() is called and after _PyGILState_Fini() is called. - See also _PyInterpreterState_Get() and _PyInterpreterState_GET(). */ + See also PyInterpreterState_Get() and _PyInterpreterState_GET(). */ PyAPI_FUNC(PyInterpreterState *) _PyGILState_GetInterpreterStateUnsafe(void); /* The implementation of sys._current_frames() Returns a dict mapping diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 43652c4405ec1a..63fc6b2129ce2a 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -108,7 +108,7 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) The caller must hold the GIL. - See also _PyInterpreterState_Get() + See also PyInterpreterState_Get() and _PyGILState_GetInterpreterStateUnsafe(). */ static inline PyInterpreterState* _PyInterpreterState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); diff --git a/Misc/NEWS.d/next/C API/2023-07-02-00-00-20.gh-issue-106320.tZWcvG.rst b/Misc/NEWS.d/next/C API/2023-07-02-00-00-20.gh-issue-106320.tZWcvG.rst new file mode 100644 index 00000000000000..145d2ce7b0ceb1 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-02-00-00-20.gh-issue-106320.tZWcvG.rst @@ -0,0 +1,3 @@ +Remove ``_PyInterpreterState_Get()`` alias to +:c:func:`PyInterpreterState_Get()` which was kept for backward compatibility +with Python 3.8. Patch by Victor Stinner. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 7f8b3cbbfcec7b..f570b4e7007156 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1104,7 +1104,7 @@ thread_run(void *boot_raw) static PyObject * thread_daemon_threads_allowed(PyObject *module, PyObject *Py_UNUSED(ignored)) { - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->feature_flags & Py_RTFLAGS_DAEMON_THREADS) { Py_RETURN_TRUE; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e67945db9af330..3d3a63a75bd2fb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6362,7 +6362,7 @@ object___reduce_ex___impl(PyObject *self, int protocol) /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/ { #define objreduce \ - (_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_Get(), objreduce)) + (_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_GET(), objreduce)) PyObject *reduce, *res; if (objreduce == NULL) { @@ -9688,7 +9688,7 @@ resolve_slotdups(PyTypeObject *type, PyObject *name) /* XXX Maybe this could be optimized more -- but is it worth it? */ /* pname and ptrs act as a little cache */ - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); #define pname _Py_INTERP_CACHED_OBJECT(interp, type_slots_pname) #define ptrs _Py_INTERP_CACHED_OBJECT(interp, type_slots_ptrs) pytype_slotdef *p, **pp; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4434bf19d43b70..74def5ada5134e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5831,7 +5831,7 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s, PyObject *errorHandler = NULL; PyObject *exc = NULL; _PyUnicode_Name_CAPI *ucnhash_capi; - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); // so we can remember if we've seen an invalid escape char or not *first_invalid_escape = NULL; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index bb1279f46cf9f7..c6b1f9ef689ee1 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -491,7 +491,7 @@ take_gil(PyThreadState *tstate) void _PyEval_SetSwitchInterval(unsigned long microseconds) { - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); gil->interval = microseconds; @@ -499,7 +499,7 @@ void _PyEval_SetSwitchInterval(unsigned long microseconds) unsigned long _PyEval_GetSwitchInterval(void) { - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); struct _gil_runtime_state *gil = interp->ceval.gil; assert(gil != NULL); return gil->interval; diff --git a/Python/hamt.c b/Python/hamt.c index 8cb94641bef251..c78b5a7fab94f0 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -2425,7 +2425,7 @@ hamt_alloc(void) } #define _empty_hamt \ - (&_Py_INTERP_SINGLETON(_PyInterpreterState_Get(), hamt_empty)) + (&_Py_INTERP_SINGLETON(_PyInterpreterState_GET(), hamt_empty)) PyHamtObject * _PyHamt_New(void) diff --git a/Python/import.c b/Python/import.c index 324fe3812bdd49..fcc0346e7f15af 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1123,7 +1123,7 @@ check_multi_interp_extensions(PyInterpreterState *interp) int _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) { - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (check_multi_interp_extensions(interp)) { assert(!_Py_IsMainInterpreter(interp)); PyErr_Format(PyExc_ImportError, diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 86d014ededc8ee..3253a0ea13033c 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1219,7 +1219,7 @@ _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* PyObject * _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) { - PyInterpreterState *is = _PyInterpreterState_Get(); + PyInterpreterState *is = _PyInterpreterState_GET(); assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); assert(0 <= event_id && event_id < PY_MONITORING_EVENTS); PyObject *callback = is->monitoring_callables[tool_id][event_id]; @@ -1678,7 +1678,7 @@ int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; @@ -1696,7 +1696,7 @@ int _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS)); if (check_tool(interp, tool_id)) { return -1; @@ -1758,7 +1758,7 @@ monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name) PyErr_SetString(PyExc_ValueError, "tool name must be a str"); return NULL; } - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->monitoring_tool_names[tool_id] != NULL) { PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id); return NULL; @@ -1782,7 +1782,7 @@ monitoring_free_tool_id_impl(PyObject *module, int tool_id) if (check_valid_tool(tool_id)) { return NULL; } - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); Py_CLEAR(interp->monitoring_tool_names[tool_id]); Py_RETURN_NONE; } @@ -1804,7 +1804,7 @@ monitoring_get_tool_impl(PyObject *module, int tool_id) if (check_valid_tool(tool_id)) { return NULL; } - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *name = interp->monitoring_tool_names[tool_id]; if (name == NULL) { Py_RETURN_NONE; @@ -1865,7 +1865,7 @@ monitoring_get_events_impl(PyObject *module, int tool_id) if (check_valid_tool(tool_id)) { return -1; } - _Py_Monitors *m = &_PyInterpreterState_Get()->monitors; + _Py_Monitors *m = &_PyInterpreterState_GET()->monitors; _PyMonitoringEventSet event_set = get_events(m, tool_id); return event_set; } @@ -1990,7 +1990,7 @@ monitoring_restart_events_impl(PyObject *module) * last restart version > instrumented version for all code objects * last restart version < current version */ - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); interp->last_restart_version = interp->monitoring_version + 1; interp->monitoring_version = interp->last_restart_version + 1; if (instrument_all_executing_code_objects(interp)) { @@ -2038,7 +2038,7 @@ static PyObject * monitoring__all_events_impl(PyObject *module) /*[clinic end generated code: output=6b7581e2dbb690f6 input=62ee9672c17b7f0e]*/ { - PyInterpreterState *interp = _PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *res = PyDict_New(); if (res == NULL) { return NULL; From feb51f3a6443d7c0148e2e7be2ed58b4c69fa265 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 02:49:18 +0200 Subject: [PATCH 219/446] gh-106320: Remove private _PyTraceMalloc C API functions (#106324) * Remove private _PyTraceMalloc C API functions: move them to the internal C API. * Don't export most of these functions anymore, but still export _PyTraceMalloc_GetTraceback() used by tests. * Rename Include/tracemalloc.h to Include/cpython/tracemalloc.h --- Include/Python.h | 2 +- Include/cpython/tracemalloc.h | 26 ++++++++++ Include/internal/pycore_tracemalloc.h | 45 +++++++++++++++++ Include/tracemalloc.h | 72 --------------------------- Lib/test/test_tracemalloc.py | 4 +- Makefile.pre.in | 2 +- Modules/_testcapi/mem.c | 18 ------- Modules/_testinternalcapi.c | 20 +++++++- PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 6 +-- 10 files changed, 99 insertions(+), 98 deletions(-) create mode 100644 Include/cpython/tracemalloc.h delete mode 100644 Include/tracemalloc.h diff --git a/Include/Python.h b/Include/Python.h index 183d07cc539b4a..07f6c202a7f126 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -103,7 +103,7 @@ #include "pystrcmp.h" #include "fileutils.h" #include "cpython/pyfpe.h" -#include "tracemalloc.h" +#include "cpython/tracemalloc.h" #include "cpython/optimizer.h" #endif /* !Py_PYTHON_H */ diff --git a/Include/cpython/tracemalloc.h b/Include/cpython/tracemalloc.h new file mode 100644 index 00000000000000..61a16ea9a9f3eb --- /dev/null +++ b/Include/cpython/tracemalloc.h @@ -0,0 +1,26 @@ +#ifndef Py_LIMITED_API +#ifndef Py_TRACEMALLOC_H +#define Py_TRACEMALLOC_H + +/* Track an allocated memory block in the tracemalloc module. + Return 0 on success, return -1 on error (failed to allocate memory to store + the trace). + + Return -2 if tracemalloc is disabled. + + If memory block is already tracked, update the existing trace. */ +PyAPI_FUNC(int) PyTraceMalloc_Track( + unsigned int domain, + uintptr_t ptr, + size_t size); + +/* Untrack an allocated memory block in the tracemalloc module. + Do nothing if the block was not tracked. + + Return -2 if tracemalloc is disabled, otherwise return 0. */ +PyAPI_FUNC(int) PyTraceMalloc_Untrack( + unsigned int domain, + uintptr_t ptr); + +#endif // !Py_TRACEMALLOC_H +#endif // !Py_LIMITED_API diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index d086adc61c319b..cfc4d1fe43999e 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -117,6 +117,51 @@ struct _tracemalloc_runtime_state { } +/* Get the traceback where a memory block was allocated. + + Return a tuple of (filename: str, lineno: int) tuples. + + Return None if the tracemalloc module is disabled or if the memory block + is not tracked by tracemalloc. + + Raise an exception and return NULL on error. */ +PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( + unsigned int domain, + uintptr_t ptr); + +/* Return non-zero if tracemalloc is tracing */ +extern int _PyTraceMalloc_IsTracing(void); + +/* Clear the tracemalloc traces */ +extern void _PyTraceMalloc_ClearTraces(void); + +/* Clear the tracemalloc traces */ +extern PyObject* _PyTraceMalloc_GetTraces(void); + +/* Clear tracemalloc traceback for an object */ +extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj); + +/* Initialize tracemalloc */ +extern int _PyTraceMalloc_Init(void); + +/* Start tracemalloc */ +extern int _PyTraceMalloc_Start(int max_nframe); + +/* Stop tracemalloc */ +extern void _PyTraceMalloc_Stop(void); + +/* Get the tracemalloc traceback limit */ +extern int _PyTraceMalloc_GetTracebackLimit(void); + +/* Get the memory usage of tracemalloc in bytes */ +extern size_t _PyTraceMalloc_GetMemory(void); + +/* Get the current size and peak size of traced memory blocks as a 2-tuple */ +extern PyObject* _PyTraceMalloc_GetTracedMemory(void); + +/* Set the peak size of traced memory blocks to the current size */ +extern void _PyTraceMalloc_ResetPeak(void); + #ifdef __cplusplus } #endif diff --git a/Include/tracemalloc.h b/Include/tracemalloc.h deleted file mode 100644 index 580027a8e365e5..00000000000000 --- a/Include/tracemalloc.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef Py_TRACEMALLOC_H -#define Py_TRACEMALLOC_H - -#ifndef Py_LIMITED_API -/* Track an allocated memory block in the tracemalloc module. - Return 0 on success, return -1 on error (failed to allocate memory to store - the trace). - - Return -2 if tracemalloc is disabled. - - If memory block is already tracked, update the existing trace. */ -PyAPI_FUNC(int) PyTraceMalloc_Track( - unsigned int domain, - uintptr_t ptr, - size_t size); - -/* Untrack an allocated memory block in the tracemalloc module. - Do nothing if the block was not tracked. - - Return -2 if tracemalloc is disabled, otherwise return 0. */ -PyAPI_FUNC(int) PyTraceMalloc_Untrack( - unsigned int domain, - uintptr_t ptr); - -/* Get the traceback where a memory block was allocated. - - Return a tuple of (filename: str, lineno: int) tuples. - - Return None if the tracemalloc module is disabled or if the memory block - is not tracked by tracemalloc. - - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( - unsigned int domain, - uintptr_t ptr); - -/* Return non-zero if tracemalloc is tracing */ -PyAPI_FUNC(int) _PyTraceMalloc_IsTracing(void); - -/* Clear the tracemalloc traces */ -PyAPI_FUNC(void) _PyTraceMalloc_ClearTraces(void); - -/* Clear the tracemalloc traces */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTraces(void); - -/* Clear tracemalloc traceback for an object */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetObjectTraceback(PyObject *obj); - -/* Initialize tracemalloc */ -PyAPI_FUNC(int) _PyTraceMalloc_Init(void); - -/* Start tracemalloc */ -PyAPI_FUNC(int) _PyTraceMalloc_Start(int max_nframe); - -/* Stop tracemalloc */ -PyAPI_FUNC(void) _PyTraceMalloc_Stop(void); - -/* Get the tracemalloc traceback limit */ -PyAPI_FUNC(int) _PyTraceMalloc_GetTracebackLimit(void); - -/* Get the memory usage of tracemalloc in bytes */ -PyAPI_FUNC(size_t) _PyTraceMalloc_GetMemory(void); - -/* Get the current size and peak size of traced memory blocks as a 2-tuple */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTracedMemory(void); - -/* Set the peak size of traced memory blocks to the current size */ -PyAPI_FUNC(void) _PyTraceMalloc_ResetPeak(void); - -#endif - -#endif /* !Py_TRACEMALLOC_H */ diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 94bcee302fe730..4af4ca3b977236 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -11,8 +11,10 @@ try: import _testcapi + import _testinternalcapi except ImportError: _testcapi = None + _testinternalcapi = None EMPTY_STRING_SIZE = sys.getsizeof(b'') @@ -1008,7 +1010,7 @@ def tearDown(self): tracemalloc.stop() def get_traceback(self): - frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr) + frames = _testinternalcapi._PyTraceMalloc_GetTraceback(self.domain, self.ptr) if frames is not None: return tracemalloc.Traceback(frames) else: diff --git a/Makefile.pre.in b/Makefile.pre.in index 54d0516ad4423b..e788e590dcbb43 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1658,7 +1658,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/structseq.h \ $(srcdir)/Include/sysmodule.h \ $(srcdir)/Include/traceback.h \ - $(srcdir)/Include/tracemalloc.h \ $(srcdir)/Include/tupleobject.h \ $(srcdir)/Include/unicodeobject.h \ $(srcdir)/Include/warnings.h \ @@ -1713,6 +1712,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/setobject.h \ $(srcdir)/Include/cpython/sysmodule.h \ $(srcdir)/Include/cpython/traceback.h \ + $(srcdir)/Include/cpython/tracemalloc.h \ $(srcdir)/Include/cpython/tupleobject.h \ $(srcdir)/Include/cpython/unicodeobject.h \ $(srcdir)/Include/cpython/warnings.h \ diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index af32e9668dda2d..16bda66af554af 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -655,23 +655,6 @@ tracemalloc_untrack(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject * -tracemalloc_get_traceback(PyObject *self, PyObject *args) -{ - unsigned int domain; - PyObject *ptr_obj; - - if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { - return NULL; - } - void *ptr = PyLong_AsVoidPtr(ptr_obj); - if (PyErr_Occurred()) { - return NULL; - } - - return _PyTraceMalloc_GetTraceback(domain, (uintptr_t)ptr); -} - static PyMethodDef test_methods[] = { {"check_pyobject_forbidden_bytes_is_freed", check_pyobject_forbidden_bytes_is_freed, METH_NOARGS}, @@ -697,7 +680,6 @@ static PyMethodDef test_methods[] = { // Tracemalloc tests {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, - {"tracemalloc_get_traceback", tracemalloc_get_traceback, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index c598d7edef8ae2..f6ae389ea05679 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1216,6 +1216,24 @@ test_pytime_object_to_timespec(PyObject *self, PyObject *args) } +static PyObject * +tracemalloc_get_traceback(PyObject *self, PyObject *args) +{ + unsigned int domain; + PyObject *ptr_obj; + + if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { + return NULL; + } + void *ptr = PyLong_AsVoidPtr(ptr_obj); + if (PyErr_Occurred()) { + return NULL; + } + + return _PyTraceMalloc_GetTraceback(domain, (uintptr_t)ptr); +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1250,7 +1268,6 @@ static PyMethodDef module_functions[] = { {"get_uop_optimizer", get_uop_optimizer, METH_NOARGS, NULL}, {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), METH_VARARGS | METH_KEYWORDS}, -// {"pending_fd_identify", pending_fd_identify, METH_VARARGS, NULL}, {"pending_identify", pending_identify, METH_VARARGS, NULL}, {"_PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS}, {"_PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS}, @@ -1266,6 +1283,7 @@ static PyMethodDef module_functions[] = { {"_PyTime_ObjectToTime_t", test_pytime_object_to_time_t, METH_VARARGS}, {"_PyTime_ObjectToTimespec", test_pytime_object_to_timespec, METH_VARARGS}, {"_PyTime_ObjectToTimeval", test_pytime_object_to_timeval, METH_VARARGS}, + {"_PyTraceMalloc_GetTraceback", tracemalloc_get_traceback, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 58abd871376a06..436381c3ea5db4 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -179,6 +179,7 @@ + @@ -320,7 +321,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 4d7b5ccf9a8a9e..4d9acf4893872d 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -219,9 +219,6 @@ Include - - Include - Include @@ -453,6 +450,9 @@ Include\cpython + + Include + Include\cpython From 8571b271e7d16fe87d669a2e1e50f5ae3732bb31 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 03:39:38 +0200 Subject: [PATCH 220/446] gh-106320: Remove private _PyInterpreterState functions (#106325) Remove private _PyThreadState and _PyInterpreterState C API functions: move them to the internal C API (pycore_pystate.h and pycore_interp.h). Don't export most of these functions anymore, but still export functions used by tests. Remove _PyThreadState_Prealloc() and _PyThreadState_Init() from the C API, but keep it in the stable API. --- Include/cpython/pystate.h | 57 ------------------------------ Include/internal/pycore_interp.h | 37 +++++++++++++++++++ Include/internal/pycore_pystate.h | 19 ++++++++-- Modules/_testcapimodule.c | 5 --- Modules/_testinternalcapi.c | 22 ++++++++++++ Modules/_xxsubinterpretersmodule.c | 6 +++- Python/compile.c | 1 + Python/frozenmain.c | 3 +- Python/pystate.c | 6 ++-- 9 files changed, 86 insertions(+), 70 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 7d9e41bc2dd7ab..e08bcdaf197628 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -40,8 +40,6 @@ PyAPI_FUNC(int) _PyInterpreterState_HasFeature(PyInterpreterState *interp, PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_RequireIDRef(PyInterpreterState *, int); -PyAPI_FUNC(PyObject *) _PyInterpreterState_GetMainModule(PyInterpreterState *); - /* State unique per thread */ @@ -261,16 +259,10 @@ struct _ts { /* other API */ -/* An alias for the internal _PyThreadState_New(), - kept for stable ABI compatibility. */ -PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *); - /* Similar to PyThreadState_Get(), but don't issue a fatal error * if it is NULL. */ PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void); -PyAPI_FUNC(PyObject *) _PyThreadState_GetDict(PyThreadState *tstate); - // Disable tracing and profiling. PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate); @@ -295,16 +287,6 @@ PyAPI_FUNC(int) PyGILState_Check(void); See also PyInterpreterState_Get() and _PyInterpreterState_GET(). */ PyAPI_FUNC(PyInterpreterState *) _PyGILState_GetInterpreterStateUnsafe(void); -/* The implementation of sys._current_frames() Returns a dict mapping - thread id to that thread's current frame. -*/ -PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void); - -/* The implementation of sys._current_exceptions() Returns a dict mapping - thread id to that thread's current exception. -*/ -PyAPI_FUNC(PyObject *) _PyThread_CurrentExceptions(void); - /* Routines for advanced debuggers, requested by David Beazley. Don't use unless you know what you are doing! */ PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Main(void); @@ -324,45 +306,6 @@ PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc( PyInterpreterState *interp, _PyFrameEvalFunction eval_frame); -PyAPI_FUNC(const PyConfig*) _PyInterpreterState_GetConfig(PyInterpreterState *interp); - -/* Get a copy of the current interpreter configuration. - - Return 0 on success. Raise an exception and return -1 on error. - - The caller must initialize 'config', using PyConfig_InitPythonConfig() - for example. - - Python must be preinitialized to call this method. - The caller must hold the GIL. - - Once done with the configuration, PyConfig_Clear() must be called to clear - it. */ -PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( - struct PyConfig *config); - -/* Set the configuration of the current interpreter. - - This function should be called during or just after the Python - initialization. - - Update the sys module with the new configuration. If the sys module was - modified directly after the Python initialization, these changes are lost. - - Some configuration like faulthandler or warnoptions can be updated in the - configuration, but don't reconfigure Python (don't enable/disable - faulthandler and don't reconfigure warnings filters). - - Return 0 on success. Raise an exception and return -1 on error. - - The configuration should come from _PyInterpreterState_GetConfigCopy(). */ -PyAPI_FUNC(int) _PyInterpreterState_SetConfig( - const struct PyConfig *config); - -// Get the configuration of the current interpreter. -// The caller must hold the GIL. -PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); - /* cross-interpreter data */ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 466ae6fbbdc4eb..a1f00df12d6ac9 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -238,6 +238,43 @@ PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *); PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *); +PyAPI_FUNC(PyObject*) _PyInterpreterState_GetMainModule(PyInterpreterState *); + +extern const PyConfig* _PyInterpreterState_GetConfig(PyInterpreterState *interp); + +/* Get a copy of the current interpreter configuration. + + Return 0 on success. Raise an exception and return -1 on error. + + The caller must initialize 'config', using PyConfig_InitPythonConfig() + for example. + + Python must be preinitialized to call this method. + The caller must hold the GIL. + + Once done with the configuration, PyConfig_Clear() must be called to clear + it. */ +PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( + struct PyConfig *config); + +/* Set the configuration of the current interpreter. + + This function should be called during or just after the Python + initialization. + + Update the sys module with the new configuration. If the sys module was + modified directly after the Python initialization, these changes are lost. + + Some configuration like faulthandler or warnoptions can be updated in the + configuration, but don't reconfigure Python (don't enable/disable + faulthandler and don't reconfigure warnings filters). + + Return 0 on success. Raise an exception and return -1 on error. + + The configuration should come from _PyInterpreterState_GetConfigCopy(). */ +PyAPI_FUNC(int) _PyInterpreterState_SetConfig( + const struct PyConfig *config); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 63fc6b2129ce2a..0659084194d293 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -123,9 +123,6 @@ static inline PyInterpreterState* _PyInterpreterState_GET(void) { PyAPI_FUNC(PyThreadState *) _PyThreadState_New(PyInterpreterState *interp); PyAPI_FUNC(void) _PyThreadState_Bind(PyThreadState *tstate); -// We keep this around exclusively for stable ABI compatibility. -PyAPI_FUNC(void) _PyThreadState_Init( - PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); @@ -133,6 +130,18 @@ extern void _PyThreadState_ClearDetached(PyThreadState *); extern void _PyThreadState_BindDetached(PyThreadState *); extern void _PyThreadState_UnbindDetached(PyThreadState *); +PyAPI_FUNC(PyObject*) _PyThreadState_GetDict(PyThreadState *tstate); + +/* The implementation of sys._current_frames() Returns a dict mapping + thread id to that thread's current frame. +*/ +extern PyObject* _PyThread_CurrentFrames(void); + +/* The implementation of sys._current_exceptions() Returns a dict mapping + thread id to that thread's current exception. +*/ +extern PyObject* _PyThread_CurrentExceptions(void); + /* Other */ @@ -161,6 +170,10 @@ PyAPI_FUNC(int) _PyOS_InterruptOccurred(PyThreadState *tstate); #define HEAD_UNLOCK(runtime) \ PyThread_release_lock((runtime)->interpreters.mutex) +// Get the configuration of the current interpreter. +// The caller must hold the GIL. +PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); + #ifdef __cplusplus } diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ec2e64f2f46fc1..398450d804f5c5 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2714,11 +2714,6 @@ test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) assert(PyDict_Check(dict)); // dict is a borrowed reference - // private _PyThreadState_GetDict() - PyObject *dict2 = _PyThreadState_GetDict(tstate); - assert(dict2 == dict); - // dict2 is a borrowed reference - // PyThreadState_GetInterpreter() PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate); assert(interp != NULL); diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index f6ae389ea05679..2e0609dcae5b7d 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1234,6 +1234,27 @@ tracemalloc_get_traceback(PyObject *self, PyObject *args) } +// Test PyThreadState C API +static PyObject * +test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) +{ + // PyThreadState_Get() + PyThreadState *tstate = PyThreadState_Get(); + assert(tstate != NULL); + + // test _PyThreadState_GetDict() + PyObject *dict = PyThreadState_GetDict(); + assert(dict != NULL); + // dict is a borrowed reference + + PyObject *dict2 = _PyThreadState_GetDict(tstate); + assert(dict2 == dict); + // dict2 is a borrowed reference + + Py_RETURN_NONE; +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1284,6 +1305,7 @@ static PyMethodDef module_functions[] = { {"_PyTime_ObjectToTimespec", test_pytime_object_to_timespec, METH_VARARGS}, {"_PyTime_ObjectToTimeval", test_pytime_object_to_timeval, METH_VARARGS}, {"_PyTraceMalloc_GetTraceback", tracemalloc_get_traceback, METH_VARARGS}, + {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 4801f37d6f6c5f..40dea170fd1f8b 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1,8 +1,12 @@ - /* interpreters module */ /* low-level access to interpreter primitives */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" +#include "pycore_interp.h" // _PyInterpreterState_GetMainModule() #include "interpreteridobject.h" diff --git a/Python/compile.c b/Python/compile.c index d83bf0855ec257..29ea2742fad0cf 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -33,6 +33,7 @@ #include "pycore_compile.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() #include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed diff --git a/Python/frozenmain.c b/Python/frozenmain.c index f8be165f7671df..767f9804903a9e 100644 --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -1,7 +1,8 @@ /* Python interpreter main program for frozen scripts */ #include "Python.h" -#include "pycore_runtime.h" // _PyRuntime_Initialize() +#include "pycore_pystate.h" // _Py_GetConfig() +#include "pycore_runtime.h" // _PyRuntime_Initialize() #include #ifdef MS_WINDOWS diff --git a/Python/pystate.c b/Python/pystate.c index 20b02ef22109e7..50ce1d06602106 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1166,7 +1166,7 @@ PyInterpreterState_GetDict(PyInterpreterState *interp) The GIL must be held. */ -PyInterpreterState * +PyInterpreterState* PyInterpreterState_Get(void) { PyThreadState *tstate = current_fast_get(&_PyRuntime); @@ -1408,7 +1408,7 @@ _PyThreadState_New(PyInterpreterState *interp) } // We keep this for stable ABI compabibility. -PyThreadState * +PyAPI_FUNC(PyThreadState*) _PyThreadState_Prealloc(PyInterpreterState *interp) { return _PyThreadState_New(interp); @@ -1416,7 +1416,7 @@ _PyThreadState_Prealloc(PyInterpreterState *interp) // We keep this around for (accidental) stable ABI compatibility. // Realistically, no extensions are using it. -void +PyAPI_FUNC(void) _PyThreadState_Init(PyThreadState *tstate) { Py_FatalError("_PyThreadState_Init() is for internal use only"); From d5bd32fb48ef8db2586b09d951514d75437b6195 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sun, 2 Jul 2023 15:07:46 +0900 Subject: [PATCH 221/446] gh-104922: remove PY_SSIZE_T_CLEAN (#106315) --- Modules/_bisectmodule.c | 1 - Modules/_bz2module.c | 2 -- Modules/_codecsmodule.c | 1 - Modules/_ctypes/_ctypes.c | 1 - Modules/_cursesmodule.c | 2 -- Modules/_dbmmodule.c | 1 - Modules/_elementtree.c | 2 -- Modules/_gdbmmodule.c | 1 - Modules/_hashopenssl.c | 2 -- Modules/_io/_iomodule.c | 1 - Modules/_io/bufferedio.c | 1 - Modules/_io/fileio.c | 1 - Modules/_io/iobase.c | 1 - Modules/_io/stringio.c | 1 - Modules/_io/textio.c | 1 - Modules/_io/winconsoleio.c | 1 - Modules/_localemodule.c | 1 - Modules/_lzmamodule.c | 2 -- Modules/_multiprocessing/multiprocessing.h | 2 -- Modules/_multiprocessing/posixshmem.c | 2 -- Modules/_sqlite/connection.h | 1 - Modules/_sqlite/cursor.h | 1 - Modules/_sqlite/microprotocols.h | 1 - Modules/_sqlite/module.h | 1 - Modules/_sqlite/row.h | 1 - Modules/_sqlite/statement.h | 1 - Modules/_sqlite/util.h | 1 - Modules/_sre/sre.c | 2 -- Modules/_ssl.c | 2 -- Modules/_stat.c | 1 - Modules/_struct.c | 2 -- Modules/_testbuffer.c | 3 --- Modules/_testcapi/float.c | 2 -- Modules/_testcapi/getargs.c | 2 -- Modules/_testcapi/structmember.c | 1 - Modules/_testcapi/unicode.c | 1 - Modules/_testcapimodule.c | 2 -- Modules/_testclinic.c | 2 -- Modules/_testinternalcapi.c | 2 -- Modules/_tkinter.c | 1 - Modules/_uuidmodule.c | 2 -- Modules/_xxtestfuzz/_xxtestfuzz.c | 1 - Modules/arraymodule.c | 1 - Modules/binascii.c | 2 -- Modules/cjkcodecs/cjkcodecs.h | 1 - Modules/cjkcodecs/multibytecodec.c | 1 - Modules/fcntlmodule.c | 3 --- Modules/itertoolsmodule.c | 1 - Modules/mmapmodule.c | 1 - Modules/posixmodule.c | 2 -- Modules/socketmodule.c | 1 - Modules/unicodedata.c | 2 -- Modules/zlibmodule.c | 2 -- Objects/bytearrayobject.c | 1 - Objects/bytes_methods.c | 1 - Objects/bytesobject.c | 2 -- Objects/exceptions.c | 1 - Objects/fileobject.c | 1 - Objects/picklebufobject.c | 1 - Objects/unicodeobject.c | 1 - PC/winreg.c | 1 - Parser/pegen.h | 1 - Parser/tokenizer.c | 1 - Python/marshal.c | 2 -- 64 files changed, 90 deletions(-) diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 60f4dc69dc05d9..9e0fd336419b44 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -7,7 +7,6 @@ Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru). # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 97bd44b4ac9694..eeefe6034998c8 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -1,7 +1,5 @@ /* _bz2 - Low-level Python interface to libbzip2. */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "structmember.h" // PyMemberDef diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index 4dfd134f1cb11e..c31c1b6d6f2bbc 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -30,7 +30,6 @@ Copyright (c) Corporation for National Research Initiatives. ------------------------------------------------------------------------ */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_codecs.h" // _PyCodec_Lookup() diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 840d0df85e9c87..a9d8a2b9cb4ad7 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -101,7 +101,6 @@ bytes(cdata) #ifndef Py_BUILD_CORE_BUILTIN # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN #include "Python.h" // windows.h must be included before pycore internal headers diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 5691a419a32f8e..1f5afa6fcd898d 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -104,8 +104,6 @@ static const char PyCursesVersion[] = "2.2"; # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_structseq.h" // _PyStructSequence_NewType() diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index 9908174c94c450..5be444d53e8da3 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -2,7 +2,6 @@ /* DBM module using dictionary interface */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 2a0eac4d2f8085..48280690a707a4 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -11,8 +11,6 @@ *-------------------------------------------------------------------- */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "structmember.h" // PyMemberDef #include "expat.h" diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 4dbb5741b2ede8..bedbdc081425c2 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -3,7 +3,6 @@ /* Author: Anthony Baxter, after dbmmodule.c */ /* Doc strings: Mitch Chapman */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "gdbm.h" diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 259db809b8664c..011cb765ed82e6 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -22,8 +22,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_hashtable.h" #include "hashlib.h" diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 7b06c1bee5a832..1a7920eebe0b61 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -7,7 +7,6 @@ Mostly written by Amaury Forgeot d'Arc */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "_iomodule.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index f30d54a5e11b0a..25376f82042836 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -7,7 +7,6 @@ Written by Amaury Forgeot d'Arc and Antoine Pitrou */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_object.h" diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 005c9ffe56f71a..1a5b61301dec58 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1,6 +1,5 @@ /* Author: Daniel Stutzbach */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_object.h" // _PyObject_GC_UNTRACK() diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 5cd679c68b1281..729a708a3fc40e 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -8,7 +8,6 @@ */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_long.h" // _PyLong_GetOne() diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index d4028451754cef..1960002d405edf 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include // offsetof() #include "pycore_object.h" diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index c8e6792657cd58..f704875280da32 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -6,7 +6,6 @@ Written by Amaury Forgeot d'Arc and Antoine Pitrou */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_codecs.h" // _PyCodecInfo_GetIncrementalDecoder() diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 15f3053957da61..452b12c138fa8b 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -6,7 +6,6 @@ Written by Steve Dower */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_object.h" // _PyObject_GC_UNTRACK() diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 1ada7305117bb7..970530facd01b0 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -9,7 +9,6 @@ This software comes with no warranty. Use at your own risk. ******************************************************************/ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_fileutils.h" diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index e34fbad230d51a..ba0987ee0abca1 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -5,8 +5,6 @@ */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "structmember.h" // PyMemberDef diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h index dfc2a8e0799a60..47257fd5d9fb26 100644 --- a/Modules/_multiprocessing/multiprocessing.h +++ b/Modules/_multiprocessing/multiprocessing.h @@ -1,8 +1,6 @@ #ifndef MULTIPROCESSING_H #define MULTIPROCESSING_H -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "structmember.h" #include "pythread.h" diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index 88c93fe313785c..debef3267f77d1 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -2,8 +2,6 @@ posixshmem - A Python extension that provides shm_open() and shm_unlink() */ -#define PY_SSIZE_T_CLEAN - #include // for shm_open() and shm_unlink() diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h index 1df92065a587a2..7a748ee3ea0c58 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_CONNECTION_H #define PYSQLITE_CONNECTION_H -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pythread.h" #include "structmember.h" diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h index 0bcdddc3e29595..42f817af7c54ad 100644 --- a/Modules/_sqlite/cursor.h +++ b/Modules/_sqlite/cursor.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_CURSOR_H #define PYSQLITE_CURSOR_H -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "statement.h" diff --git a/Modules/_sqlite/microprotocols.h b/Modules/_sqlite/microprotocols.h index 6bde9d01f45299..8a8c33525ee53b 100644 --- a/Modules/_sqlite/microprotocols.h +++ b/Modules/_sqlite/microprotocols.h @@ -26,7 +26,6 @@ #ifndef PSYCOPG_MICROPROTOCOLS_H #define PSYCOPG_MICROPROTOCOLS_H 1 -#define PY_SSIZE_T_CLEAN #include /** exported functions **/ diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h index daa22091d38ad7..a4ca45cf6326a9 100644 --- a/Modules/_sqlite/module.h +++ b/Modules/_sqlite/module.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_MODULE_H #define PYSQLITE_MODULE_H -#define PY_SSIZE_T_CLEAN #include "Python.h" #define LEGACY_TRANSACTION_CONTROL -1 diff --git a/Modules/_sqlite/row.h b/Modules/_sqlite/row.h index b51909817584ba..d42b781e493177 100644 --- a/Modules/_sqlite/row.h +++ b/Modules/_sqlite/row.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_ROW_H #define PYSQLITE_ROW_H -#define PY_SSIZE_T_CLEAN #include "Python.h" typedef struct _Row diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h index 11a6464b1a1c2b..b18f170ebb0708 100644 --- a/Modules/_sqlite/statement.h +++ b/Modules/_sqlite/statement.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_STATEMENT_H #define PYSQLITE_STATEMENT_H -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "connection.h" diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h index a22bcd82d2a05b..68b1a8cb67ace3 100644 --- a/Modules/_sqlite/util.h +++ b/Modules/_sqlite/util.h @@ -23,7 +23,6 @@ #ifndef PYSQLITE_UTIL_H #define PYSQLITE_UTIL_H -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pythread.h" #include "sqlite3.h" diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 328e4be2fb5e43..3f11916f9e1726 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -38,8 +38,6 @@ static const char copyright[] = " SRE 2.2.2 Copyright (c) 1997-2002 by Secret Labs AB "; -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 4254fde0f5190b..df1496925f678e 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -25,8 +25,6 @@ #endif #define OPENSSL_NO_DEPRECATED 1 -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_weakref.h" // _PyWeakref_GET_REF() diff --git a/Modules/_stat.c b/Modules/_stat.c index 4218799103b59d..9747d848cbacb8 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -11,7 +11,6 @@ * */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #ifdef __cplusplus diff --git a/Modules/_struct.c b/Modules/_struct.c index 4f9478bd98095d..0a6f076aac0c53 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -7,8 +7,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index 63ed4dc6ca80e1..5101834cfe1387 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -1,9 +1,6 @@ /* C Extension module to test all aspects of PEP-3118. Written by Stefan Krah. */ - -#define PY_SSIZE_T_CLEAN - #include "Python.h" diff --git a/Modules/_testcapi/float.c b/Modules/_testcapi/float.c index 33cbda83a81af7..cff53fb950fcc6 100644 --- a/Modules/_testcapi/float.c +++ b/Modules/_testcapi/float.c @@ -1,5 +1,3 @@ -#define PY_SSIZE_T_CLEAN - #include "parts.h" #include "clinic/float.c.h" diff --git a/Modules/_testcapi/getargs.c b/Modules/_testcapi/getargs.c index a473c41f60af3c..10a1c1dd05253d 100644 --- a/Modules/_testcapi/getargs.c +++ b/Modules/_testcapi/getargs.c @@ -3,8 +3,6 @@ * APIs that parse and build arguments. */ -#define PY_SSIZE_T_CLEAN - #include "parts.h" static PyObject * diff --git a/Modules/_testcapi/structmember.c b/Modules/_testcapi/structmember.c index 0fb872a4328d60..8522dc962efa40 100644 --- a/Modules/_testcapi/structmember.c +++ b/Modules/_testcapi/structmember.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include "parts.h" #include // for offsetof() diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 73929eaffc676d..367d2af1413e57 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -1,6 +1,5 @@ #include // ptrdiff_t -#define PY_SSIZE_T_CLEAN #include "parts.h" static struct PyModuleDef *_testcapimodule = NULL; // set at initialization diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 398450d804f5c5..ce1131743eb2a4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -17,8 +17,6 @@ /* Always enable assertions */ #undef NDEBUG -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "frameobject.h" // PyFrame_New #include "marshal.h" // PyMarshal_WriteLongToFile diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 6ff55a2755cf5a..26cdb4371ca24c 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -5,8 +5,6 @@ /* Always enable assertions */ #undef NDEBUG -#define PY_SSIZE_T_CLEAN - #include "Python.h" diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 2e0609dcae5b7d..971b8efb5fd9a4 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -9,8 +9,6 @@ /* Always enable assertions */ #undef NDEBUG -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "frameobject.h" #include "interpreteridobject.h" // _PyInterpreterID_LookUp() diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 97e5b2f738aa2a..76af803bd6eefb 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -21,7 +21,6 @@ Copyright (C) 1994 Steen Lumholt. */ -#define PY_SSIZE_T_CLEAN #ifndef Py_BUILD_CORE_BUILTIN # define Py_BUILD_CORE_MODULE 1 #endif diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c index ed3b2fedfd4d88..2f5be1c5144d83 100644 --- a/Modules/_uuidmodule.c +++ b/Modules/_uuidmodule.c @@ -3,8 +3,6 @@ * DCE compatible Universally Unique Identifier library. */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #if defined(HAVE_UUID_H) // AIX, FreeBSD, libuuid with pkgconf diff --git a/Modules/_xxtestfuzz/_xxtestfuzz.c b/Modules/_xxtestfuzz/_xxtestfuzz.c index e0694de6719df0..a2dbabce71ed67 100644 --- a/Modules/_xxtestfuzz/_xxtestfuzz.c +++ b/Modules/_xxtestfuzz/_xxtestfuzz.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include #include #include diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 15f7766a8dd284..f43a23467976b8 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -7,7 +7,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallMethod() #include "pycore_moduleobject.h" // _PyModule_GetState() diff --git a/Modules/binascii.c b/Modules/binascii.c index 356947d43e43a9..cf9328795c2bcc 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -57,8 +57,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_long.h" // _PyLong_DigitValue #include "pycore_strhex.h" // _Py_strhex_bytes_with_sep() diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index 36bc7024df9acc..48cdcfb3ad3087 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -7,7 +7,6 @@ #ifndef _CJKCODECS_H_ #define _CJKCODECS_H_ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "multibytecodec.h" diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 1070a751ffe638..cf437d09f1fe8d 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -4,7 +4,6 @@ * Written by Hye-Shik Chang */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" // PyMemberDef #include "multibytecodec.h" diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index 6ca0b62bc5dca8..e530621fd269a1 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -1,8 +1,5 @@ - /* fcntl module */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #ifdef HAVE_SYS_FILE_H diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index ae63bae79d5d07..13ff253f560b04 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 6bde9939eaa2ca..fef27123a3282b 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -22,7 +22,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN #include #include "pycore_bytesobject.h" // _PyBytes_Find() #include "pycore_fileutils.h" // _Py_stat_struct diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d73886f14cb9ec..b9f42476e6b82c 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7,8 +7,6 @@ of the compiler used. Different compilers define their own feature test macro, e.g. '_MSC_VER'. */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #ifdef __VXWORKS__ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 3add80233522b9..1d3f34b857a1d2 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -105,7 +105,6 @@ Local naming conventions: # pragma weak inet_aton #endif -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_fileutils.h" // _Py_set_inheritable() #include "pycore_moduleobject.h" // _PyModule_GetState diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 7be4d83c6f070f..b6e50528a23c86 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -16,8 +16,6 @@ # define Py_BUILD_CORE_MODULE 1 #endif -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI #include "structmember.h" // PyMemberDef diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 534d065765f0f9..c0f6b96f51baba 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -3,8 +3,6 @@ /* Windows users: read Python's PCbuild\readme.txt */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "structmember.h" // PyMemberDef #include "zlib.h" diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 944ec65b64f6a2..18a24a369a64c1 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1,6 +1,5 @@ /* PyByteArray (bytearray) implementation */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index 33aa9c3db6e805..c1bc6383df30ce 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -1,4 +1,3 @@ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index bf54ec1d51d209..477bc4d31e812b 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1,7 +1,5 @@ /* bytes object implementation */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytesobject.h" // _PyBytes_Find(), _PyBytes_Repeat() diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 2bfa07ea3121f4..85cf2cca16516b 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -4,7 +4,6 @@ * Thanks go to Tim Peters and Michael Hudson for debugging. */ -#define PY_SSIZE_T_CLEAN #include #include #include "pycore_abstract.h" // _PyObject_RealIsSubclass() diff --git a/Objects/fileobject.c b/Objects/fileobject.c index e99e155f2b8c98..6d980a1b379166 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -1,6 +1,5 @@ /* File object implementation (what's left of it -- see io.py) */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_runtime.h" // _PyRuntime diff --git a/Objects/picklebufobject.c b/Objects/picklebufobject.c index aaa852cfbb05b0..ca83a0a0806ce1 100644 --- a/Objects/picklebufobject.c +++ b/Objects/picklebufobject.c @@ -1,6 +1,5 @@ /* PickleBuffer object implementation */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 74def5ada5134e..79402714f23b9d 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -38,7 +38,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_atomic_funcs.h" // _Py_atomic_size_get() diff --git a/PC/winreg.c b/PC/winreg.c index 279d48f792b96a..aa2055c7e619d2 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -12,7 +12,6 @@ */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_object.h" // _PyObject_Init() #include "pycore_moduleobject.h" diff --git a/Parser/pegen.h b/Parser/pegen.h index fe13d10e6b83e3..5f29285951e812 100644 --- a/Parser/pegen.h +++ b/Parser/pegen.h @@ -1,7 +1,6 @@ #ifndef PEGEN_H #define PEGEN_H -#define PY_SSIZE_T_CLEAN #include #include #include diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 6bdf371a7adf03..f19198600fa018 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1,7 +1,6 @@ /* Tokenizer implementation */ -#define PY_SSIZE_T_CLEAN #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() diff --git a/Python/marshal.c b/Python/marshal.c index 7cfc7cc00306f5..517220a4463cf3 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -6,8 +6,6 @@ Version 3 of this protocol properly supports circular links and sharing. */ -#define PY_SSIZE_T_CLEAN - #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_code.h" // _PyCode_New() From 5950e7dbfcd9307c7e74184a1586ef99f9f35c3b Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sun, 2 Jul 2023 17:15:28 +0300 Subject: [PATCH 222/446] gh-106217: Truncate the issue body size of `new-bugs-announce-notifier` (#106329) Co-authored-by: Hugo van Kemenade --- .github/workflows/new-bugs-announce-notifier.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index 73806c5d6d58af..e3572db670693e 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -41,7 +41,10 @@ jobs: url : issue.data.html_url, labels : issue.data.labels.map(label => { return label.name }).join(", "), assignee : issue.data.assignees.map(assignee => { return assignee.login }), - body : issue.data.body + // We need to truncate the body size, because the max size for + // the whole payload is 16kb. We want to be safe and assume that + // body can take up to ~8kb of space. + body : issue.data.body.substring(8000) }; const data = { From 20b7c79b9d67a761aaf818d3b92498ea0b0d80d9 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Mon, 3 Jul 2023 00:54:35 +0900 Subject: [PATCH 223/446] gh-104922: Doc: add note about PY_SSIZE_T_CLEAN (#106314) Add note about PY_SSIZE_T_CLEAN in extending and embedding document. --- Doc/extending/embedding.rst | 7 +++++++ Doc/extending/extending.rst | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst index 1470029b804779..bd1abe36cbb80e 100644 --- a/Doc/extending/embedding.rst +++ b/Doc/extending/embedding.rst @@ -87,6 +87,13 @@ perform some operation on a file. :: Py_ExitStatusException(status); } +.. note:: + + ``#define PY_SSIZE_T_CLEAN`` was used to indicate that ``Py_ssize_t`` should be + used in some APIs instead of ``int``. + It is not necessary since Python 3.13, but we keep it here for backward compatibility. + See :ref:`arg-parsing-string-and-buffers` for a description of this macro. + Setting :c:member:`PyConfig.program_name` should be called before :c:func:`Py_InitializeFromConfig` to inform the interpreter about paths to Python run-time libraries. Next, the Python interpreter is initialized with diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index ef93848840861c..7d08bb9f6b8dd8 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -69,8 +69,10 @@ the module and a copyright notice if you like). headers on some systems, you *must* include :file:`Python.h` before any standard headers are included. - It is recommended to always define ``PY_SSIZE_T_CLEAN`` before including - ``Python.h``. See :ref:`arg-parsing-string-and-buffers` for a description of this macro. + ``#define PY_SSIZE_T_CLEAN`` was used to indicate that ``Py_ssize_t`` should be + used in some APIs instead of ``int``. + It is not necessary since Python 3.13, but we keep it here for backward compatibility. + See :ref:`arg-parsing-string-and-buffers` for a description of this macro. All user-visible symbols defined by :file:`Python.h` have a prefix of ``Py`` or ``PY``, except those defined in standard header files. For convenience, and From 9a51a419619bb9dd1075d683708c57803c5d48c7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 18:11:45 +0200 Subject: [PATCH 224/446] gh-106320: Remove private _PyInterpreterState functions (#106335) Remove private _PyThreadState and _PyInterpreterState C API functions: move them to the internal C API (pycore_pystate.h and pycore_interp.h). Don't export most of these functions anymore, but still export functions used by tests. Remove _PyThreadState_Prealloc() and _PyThreadState_Init() from the C API, but keep it in the stable API. From bc7eb1708452da59c22782c487ae7f05f1788970 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 18:37:37 +0200 Subject: [PATCH 225/446] gh-106320: Use _PyInterpreterState_GET() (#106336) Replace PyInterpreterState_Get() with inlined _PyInterpreterState_GET(). --- Modules/_asynciomodule.c | 2 +- Modules/_io/bufferedio.c | 2 +- Modules/_posixsubprocess.c | 2 +- Modules/_testinternalcapi.c | 6 +++--- Modules/_typingmodule.c | 7 ++++--- Modules/_winapi.c | 3 ++- Objects/typevarobject.c | 22 +++++++++++----------- Python/codecs.c | 4 ++-- Python/instrumentation.c | 10 ++++------ Python/optimizer.c | 9 ++++----- Python/pystate.c | 2 +- 11 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 5b28f2dd28a221..05f94ef9ed2816 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -527,7 +527,7 @@ future_init(FutureObj *fut, PyObject *loop) if (is_true < 0) { return -1; } - if (is_true && !_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) { + if (is_true && !_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) { /* Only try to capture the traceback if the interpreter is not being finalized. The original motivation to add a `_Py_IsFinalizing()` call was to prevent SIGSEGV when a Future is created in a __del__ diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 25376f82042836..9c6a9cddba2258 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -292,7 +292,7 @@ _enter_buffered_busy(buffered *self) "reentrant call inside %R", self); return 0; } - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); relax_locking = _Py_IsInterpreterFinalizing(interp); Py_BEGIN_ALLOW_THREADS if (!relax_locking) diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 52e1d2faf3e9fa..6caa4b8852911e 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -1025,7 +1025,7 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, int *c_fds_to_keep = NULL; Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep); - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if ((preexec_fn != Py_None) && interp->finalizing) { PyErr_SetString(PyExc_RuntimeError, "preexec_fn not supported at interpreter shutdown"); diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 971b8efb5fd9a4..4875ee7bed1683 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -559,7 +559,7 @@ static PyObject * set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args)) { module_state *state = get_module_state(self); - _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), _PyEval_EvalFrameDefault); + _PyInterpreterState_SetEvalFrameFunc(_PyInterpreterState_GET(), _PyEval_EvalFrameDefault); Py_CLEAR(state->record_list); Py_RETURN_NONE; } @@ -587,7 +587,7 @@ set_eval_frame_record(PyObject *self, PyObject *list) return NULL; } Py_XSETREF(state->record_list, Py_NewRef(list)); - _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), record_eval); + _PyInterpreterState_SetEvalFrameFunc(_PyInterpreterState_GET(), record_eval); Py_RETURN_NONE; } @@ -883,7 +883,7 @@ pending_threadfunc(PyObject *self, PyObject *args, PyObject *kwargs) { return NULL; } - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); /* create the reference for the callbackwhile we hold the lock */ Py_INCREF(callable); diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index 39a124a26adf31..59d3a80a9305db 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -5,8 +5,9 @@ #endif #include "Python.h" -#include "internal/pycore_interp.h" -#include "internal/pycore_typevarobject.h" +#include "pycore_interp.h" +#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_typevarobject.h" #include "clinic/_typingmodule.c.h" /*[clinic input] @@ -44,7 +45,7 @@ PyDoc_STRVAR(typing_doc, static int _typing_exec(PyObject *m) { - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); #define EXPORT_TYPE(name, typename) \ if (PyModule_AddObjectRef(m, name, \ diff --git a/Modules/_winapi.c b/Modules/_winapi.c index a7e6bb582fc64d..d4291f557b6a66 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -36,6 +36,7 @@ #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_pystate.h" // _PyInterpreterState_GET #include "structmember.h" // PyMemberDef @@ -133,7 +134,7 @@ overlapped_dealloc(OverlappedObject *self) { /* The operation is no longer pending -- nothing to do. */ } - else if (_Py_IsInterpreterFinalizing(PyInterpreterState_Get())) + else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET())) { /* The operation is still pending -- give a warning. This will probably only happen on Windows XP. */ diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 406a6eb76e3a8a..0b44f84b6f01d2 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -1,6 +1,6 @@ // TypeVar, TypeVarTuple, and ParamSpec #include "Python.h" -#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK +#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK #include "pycore_typevarobject.h" #include "pycore_unionobject.h" // _Py_union_type_or #include "structmember.h" @@ -144,7 +144,7 @@ static int contains_typevartuple(PyTupleObject *params) { Py_ssize_t n = PyTuple_GET_SIZE(params); - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.typevartuple_type; for (Py_ssize_t i = 0; i < n; i++) { PyObject *param = PyTuple_GET_ITEM(params, i); if (Py_IS_TYPE(param, tp)) { @@ -165,7 +165,7 @@ unpack_typevartuples(PyObject *params) if (new_params == NULL) { return NULL; } - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.typevartuple_type; for (Py_ssize_t i = 0; i < n; i++) { PyObject *param = PyTuple_GET_ITEM(params, i); if (Py_IS_TYPE(param, tp)) { @@ -291,7 +291,7 @@ typevar_alloc(PyObject *name, PyObject *bound, PyObject *evaluate_bound, bool covariant, bool contravariant, bool infer_variance, PyObject *module) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevar_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.typevar_type; assert(tp != NULL); typevarobject *tv = PyObject_GC_New(typevarobject, tp); if (tv == NULL) { @@ -576,7 +576,7 @@ paramspecargs_repr(PyObject *self) { paramspecattrobject *psa = (paramspecattrobject *)self; - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type; if (Py_IS_TYPE(psa->__origin__, tp)) { return PyUnicode_FromFormat("%U.args", ((paramspecobject *)psa->__origin__)->name); @@ -656,7 +656,7 @@ paramspeckwargs_repr(PyObject *self) { paramspecattrobject *psk = (paramspecattrobject *)self; - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type; if (Py_IS_TYPE(psk->__origin__, tp)) { return PyUnicode_FromFormat("%U.kwargs", ((paramspecobject *)psk->__origin__)->name); @@ -789,14 +789,14 @@ static PyMemberDef paramspec_members[] = { static PyObject * paramspec_args(PyObject *self, void *unused) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspecargs_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspecargs_type; return (PyObject *)paramspecattr_new(tp, self); } static PyObject * paramspec_kwargs(PyObject *self, void *unused) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspeckwargs_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspeckwargs_type; return (PyObject *)paramspecattr_new(tp, self); } @@ -810,7 +810,7 @@ static paramspecobject * paramspec_alloc(PyObject *name, PyObject *bound, bool covariant, bool contravariant, bool infer_variance, PyObject *module) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.paramspec_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.paramspec_type; paramspecobject *ps = PyObject_GC_New(paramspecobject, tp); if (ps == NULL) { return NULL; @@ -1059,7 +1059,7 @@ static PyMemberDef typevartuple_members[] = { static typevartupleobject * typevartuple_alloc(PyObject *name, PyObject *module) { - PyTypeObject *tp = PyInterpreterState_Get()->cached_objects.typevartuple_type; + PyTypeObject *tp = _PyInterpreterState_GET()->cached_objects.typevartuple_type; typevartupleobject *tvt = PyObject_GC_New(typevartupleobject, tp); if (tvt == NULL) { return NULL; @@ -1598,7 +1598,7 @@ _Py_subscript_generic(PyThreadState* unused, PyObject *params) { params = unpack_typevartuples(params); - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->cached_objects.generic_type == NULL) { PyErr_SetString(PyExc_SystemError, "Cannot find Generic type"); return NULL; diff --git a/Python/codecs.c b/Python/codecs.c index 1983f56ba204c1..f9f23005debb1f 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -11,7 +11,7 @@ Copyright (c) Corporation for National Research Initiatives. #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_interp.h" // PyInterpreterState.codec_search_path -#include "pycore_pyerrors.h" // _PyErr_FormatNote() +#include "pycore_pyerrors.h" // _PyErr_FormatNote() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI #include @@ -55,7 +55,7 @@ int PyCodec_Register(PyObject *search_function) int PyCodec_Unregister(PyObject *search_function) { - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *codec_search_path = interp->codec_search_path; /* Do nothing if codec_search_path is not created yet or was cleared. */ if (codec_search_path == NULL) { diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 3253a0ea13033c..03d7d2f215af7c 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1,5 +1,3 @@ - - #include "Python.h" #include "pycore_call.h" #include "pycore_frame.h" @@ -9,7 +7,7 @@ #include "pycore_object.h" #include "pycore_opcode.h" #include "pycore_pyerrors.h" -#include "pycore_pystate.h" +#include "pycore_pystate.h" // _PyInterpreterState_GET() /* Uncomment this to dump debugging output when assertions fail */ // #define INSTRUMENT_DEBUG 1 @@ -390,7 +388,7 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) fprintf(out, "NULL\n"); return; } - dump_monitors("Global", PyInterpreterState_Get()->monitors, out); + dump_monitors("Global", _PyInterpreterState_GET()->monitors, out); dump_monitors("Code", data->local_monitors, out); dump_monitors("Active", data->active_monitors, out); int code_len = (int)Py_SIZE(code); @@ -449,7 +447,7 @@ sanity_check_instrumentation(PyCodeObject *code) if (data == NULL) { return; } - _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors; + _Py_Monitors active_monitors = _PyInterpreterState_GET()->monitors; if (code->_co_monitoring) { _Py_Monitors local_monitors = code->_co_monitoring->local_monitors; active_monitors = monitors_or(active_monitors, local_monitors); @@ -740,7 +738,7 @@ remove_tools(PyCodeObject * code, int offset, int event, int tools) static bool tools_is_subset_for_event(PyCodeObject * code, int event, int tools) { - int global_tools = PyInterpreterState_Get()->monitors.tools[event]; + int global_tools = _PyInterpreterState_GET()->monitors.tools[event]; int local_tools = code->_co_monitoring->local_monitors.tools[event]; return tools == ((global_tools | local_tools) & tools); } diff --git a/Python/optimizer.c b/Python/optimizer.c index 9d77ab4ff879bb..b00825ade16e07 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1,10 +1,9 @@ - #include "Python.h" #include "opcode.h" #include "pycore_interp.h" #include "pycore_opcode.h" #include "opcode_metadata.h" -#include "pycore_pystate.h" +#include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_uops.h" #include "cpython/optimizer.h" #include @@ -125,7 +124,7 @@ _PyOptimizerObject _PyOptimizer_Default = { _PyOptimizerObject * PyUnstable_GetOptimizer(void) { - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp->optimizer == &_PyOptimizer_Default) { return NULL; } @@ -138,7 +137,7 @@ PyUnstable_GetOptimizer(void) void PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer) { - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (optimizer == NULL) { optimizer = &_PyOptimizer_Default; } @@ -155,7 +154,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI { PyCodeObject *code = (PyCodeObject *)frame->f_executable; assert(PyCode_Check(code)); - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); if (!has_space_for_executor(code, src)) { goto jump_to_destination; } diff --git a/Python/pystate.c b/Python/pystate.c index 50ce1d06602106..a9b404bd5c93e3 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2835,7 +2835,7 @@ _PyInterpreterState_GetConfig(PyInterpreterState *interp) int _PyInterpreterState_GetConfigCopy(PyConfig *config) { - PyInterpreterState *interp = PyInterpreterState_Get(); + PyInterpreterState *interp = _PyInterpreterState_GET(); PyStatus status = _PyConfig_Copy(config, &interp->config); if (PyStatus_Exception(status)) { From dbefa88b27ee1f124f782363b139aee3f1ccf590 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Mon, 3 Jul 2023 00:50:40 +0800 Subject: [PATCH 226/446] gh-106078: Move DecimalException to _decimal state (#106301) --- Modules/_decimal/_decimal.c | 17 +++++++++-------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index b7cb19515b3002..da623725003428 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -46,6 +46,9 @@ typedef struct { PyTypeObject *PyDec_Type; PyTypeObject *PyDecSignalDict_Type; PyTypeObject *DecimalTuple; + + /* Top level Exception; inherits from ArithmeticError */ + PyObject *DecimalException; } decimal_state; static decimal_state global_state; @@ -164,9 +167,6 @@ typedef struct { PyObject *ex; /* corresponding exception */ } DecCondMap; -/* Top level Exception; inherits from ArithmeticError */ -static PyObject *DecimalException = NULL; - /* Exceptions that correspond to IEEE signals */ #define SUBNORMAL 5 #define INEXACT 6 @@ -5902,10 +5902,10 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddType(m, state->DecimalTuple)); /* Create top level exception */ - ASSIGN_PTR(DecimalException, PyErr_NewException( + ASSIGN_PTR(state->DecimalException, PyErr_NewException( "decimal.DecimalException", PyExc_ArithmeticError, NULL)); - CHECK_INT(PyModule_AddObject(m, "DecimalException", Py_NewRef(DecimalException))); + CHECK_INT(PyModule_AddType(m, (PyTypeObject *)state->DecimalException)); /* Create signal tuple */ ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); @@ -5918,10 +5918,11 @@ PyInit__decimal(void) switch (cm->flag) { case MPD_Float_operation: - base = PyTuple_Pack(2, DecimalException, PyExc_TypeError); + base = PyTuple_Pack(2, state->DecimalException, PyExc_TypeError); break; case MPD_Division_by_zero: - base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError); + base = PyTuple_Pack(2, state->DecimalException, + PyExc_ZeroDivisionError); break; case MPD_Overflow: base = PyTuple_Pack(2, signal_map[INEXACT].ex, @@ -5933,7 +5934,7 @@ PyInit__decimal(void) signal_map[SUBNORMAL].ex); break; default: - base = PyTuple_Pack(1, DecimalException); + base = PyTuple_Pack(1, state->DecimalException); break; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 1131edff265ee4..8fdc54df2b0722 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -393,7 +393,6 @@ Modules/xxlimited_35.c - Xxo_Type - ## exception types Modules/_ctypes/_ctypes.c - PyExc_ArgError - Modules/_cursesmodule.c - PyCursesError - -Modules/_decimal/_decimal.c - DecimalException - Modules/_tkinter.c - Tkinter_TclError - Modules/xxlimited_35.c - ErrorObject - Modules/xxmodule.c - ErrorObject - From c38c66687f148991031914f12ebd5c42d6e26b5b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 23:19:59 +0200 Subject: [PATCH 227/446] gh-106320: Add pycore_complexobject.h header file (#106339) Add internal pycore_complexobject.h header file. Move _Py_c_xxx() functions and _PyComplex_FormatAdvancedWriter() function to this new header file. --- Include/cpython/complexobject.h | 21 ---------------- Include/internal/pycore_complexobject.h | 33 +++++++++++++++++++++++++ Makefile.pre.in | 1 + Modules/cmathmodule.c | 1 + Objects/complexobject.c | 1 + Objects/stringlib/unicode_format.h | 1 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ 8 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 Include/internal/pycore_complexobject.h diff --git a/Include/cpython/complexobject.h b/Include/cpython/complexobject.h index b7d7283ae88965..b524ec42c24371 100644 --- a/Include/cpython/complexobject.h +++ b/Include/cpython/complexobject.h @@ -7,16 +7,6 @@ typedef struct { double imag; } Py_complex; -/* Operations on complex numbers from complexmodule.c */ - -PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex); -PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex); -PyAPI_FUNC(double) _Py_c_abs(Py_complex); - /* Complex object interface */ /* @@ -31,14 +21,3 @@ typedef struct { PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex); PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op); - -#ifdef Py_BUILD_CORE -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -extern int _PyComplex_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); -#endif // Py_BUILD_CORE diff --git a/Include/internal/pycore_complexobject.h b/Include/internal/pycore_complexobject.h new file mode 100644 index 00000000000000..fb344b7bb79bd8 --- /dev/null +++ b/Include/internal/pycore_complexobject.h @@ -0,0 +1,33 @@ +#ifndef Py_INTERNAL_COMPLEXOBJECT_H +#define Py_INTERNAL_COMPLEXOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +/* Operations on complex numbers from complexmodule.c */ + +PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_diff(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_neg(Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_prod(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_quot(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) _Py_c_pow(Py_complex, Py_complex); +PyAPI_FUNC(double) _Py_c_abs(Py_complex); + +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +extern int _PyComplex_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_COMPLEXOBJECT_H diff --git a/Makefile.pre.in b/Makefile.pre.in index e788e590dcbb43..7560d17e3796f0 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1734,6 +1734,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_code.h \ $(srcdir)/Include/internal/pycore_codecs.h \ $(srcdir)/Include/internal/pycore_compile.h \ + $(srcdir)/Include/internal/pycore_complexobject.h \ $(srcdir)/Include/internal/pycore_condvar.h \ $(srcdir)/Include/internal/pycore_context.h \ $(srcdir)/Include/internal/pycore_dict.h \ diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 1a31bdc824bb03..db8b321e72e8ce 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -7,6 +7,7 @@ #endif #include "Python.h" +#include "pycore_complexobject.h" // _Py_c_neg() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR /* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from float.h. We assume that FLT_RADIX is either 2 or 16. */ diff --git a/Objects/complexobject.c b/Objects/complexobject.c index aee03ddfb07aec..12968a63cd6fdd 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -7,6 +7,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_object.h" // _PyObject_Init() #include "pycore_pymath.h" // _Py_ADJUST_ERANGE2() diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index f4ba0a92776a97..91c71ab5736c25 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -2,6 +2,7 @@ unicode_format.h -- implementation of str.format(). */ +#include "pycore_complexobject.h" // _PyComplex_FormatAdvancedWriter() #include "pycore_floatobject.h" // _PyFloat_FormatAdvancedWriter() /************************************************************************/ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 436381c3ea5db4..79ce2d3d14017e 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -212,6 +212,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 4d9acf4893872d..d47a22909e1e3a 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -543,6 +543,9 @@ Include\internal + + Include\internal + Include\internal From 4e3aa7cd312759922556ee96aa42033c375027e2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 2 Jul 2023 23:56:58 +0200 Subject: [PATCH 228/446] gh-106320: _testcapi avoids private _PyUnicode_EqualToASCIIString() (#106341) Replace private _PyUnicode_EqualToASCIIString() with public PyUnicode_CompareWithASCIIString(). --- Modules/_testcapi/unicode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 367d2af1413e57..9c2760c3f763a6 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -1100,7 +1100,7 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored)) } \ else if (result == NULL) \ return NULL; \ - else if (!_PyUnicode_EqualToASCIIString(result, EXPECTED)) { \ + else if (PyUnicode_CompareWithASCIIString(result, EXPECTED) != 0) { \ PyErr_Format(PyExc_AssertionError, \ "test_string_from_format: failed at \"%s\" " \ "expected \"%s\" got \"%s\"", \ From 569887aa9da0da2eb2e2ad7d6a7496290f223ab0 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 01:42:38 +0200 Subject: [PATCH 229/446] gh-104050: Add more type hints to Argument Clinic DSLParser() (#106343) Annotate the following method signatures: - state_dsl_start() - state_parameter_docstring_start() - state_parameters_start() Inverting ignore_line() logic, add type hints (including type guard) to it, and rename to valid_line(). --- Tools/clinic/clinic.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 43b7a9d9ac4aa7..27d3d572868883 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -29,7 +29,15 @@ from collections.abc import Callable from types import FunctionType, NoneType -from typing import Any, Final, NamedTuple, NoReturn, Literal, overload +from typing import ( + Any, + Final, + Literal, + NamedTuple, + NoReturn, + TypeGuard, + overload, +) # TODO: # @@ -4471,17 +4479,20 @@ def parse(self, block: Block) -> None: block.output = self.saved_output @staticmethod - def ignore_line(line): + def valid_line(line: str | None) -> TypeGuard[str]: + if line is None: + return False + # ignore comment-only lines if line.lstrip().startswith('#'): - return True + return False # Ignore empty lines too # (but not in docstring sections!) if not line.strip(): - return True + return False - return False + return True @staticmethod def calculate_indent(line: str) -> int: @@ -4497,9 +4508,9 @@ def next( if line is not None: self.state(line) - def state_dsl_start(self, line): + def state_dsl_start(self, line: str | None) -> None: # self.block = self.ClinicOutputBlock(self) - if self.ignore_line(line): + if not self.valid_line(line): return # is it a directive? @@ -4716,8 +4727,8 @@ def state_modulename_name(self, line): ps_start, ps_left_square_before, ps_group_before, ps_required, \ ps_optional, ps_group_after, ps_right_square_after = range(7) - def state_parameters_start(self, line): - if self.ignore_line(line): + def state_parameters_start(self, line: str) -> None: + if not self.valid_line(line): return # if this line is not indented, we have no parameters @@ -4742,7 +4753,7 @@ def state_parameter(self, line): line = self.parameter_continuation + ' ' + line.lstrip() self.parameter_continuation = '' - if self.ignore_line(line): + if not self.valid_line(line): return assert self.indent.depth == 2 @@ -5075,7 +5086,7 @@ def parse_special_symbol(self, symbol): fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") p.kind = inspect.Parameter.POSITIONAL_ONLY - def state_parameter_docstring_start(self, line): + def state_parameter_docstring_start(self, line: str) -> None: self.parameter_docstring_indent = len(self.indent.margin) assert self.indent.depth == 3 return self.next(self.state_parameter_docstring, line) From 987b712b4aeeece336eed24fcc87a950a756c3e2 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 2 Jul 2023 20:22:40 -0700 Subject: [PATCH 230/446] Replace the esoteric term 'datum' when describing dict comprehensions (#106119) --- Doc/reference/expressions.rst | 22 +++++++++++----------- Doc/reference/simple_stmts.rst | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 0c700f908d6878..ce1c9a59d58353 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -298,27 +298,27 @@ Dictionary displays .. index:: pair: dictionary; display pair: dictionary; comprehensions - key, datum, key/datum pair + key, value, key/value pair pair: object; dictionary single: {} (curly brackets); dictionary expression single: : (colon); in dictionary expressions single: , (comma); in dictionary displays -A dictionary display is a possibly empty series of key/datum pairs enclosed in -curly braces: +A dictionary display is a possibly empty series of dict items (key/value pairs) +enclosed in curly braces: .. productionlist:: python-grammar - dict_display: "{" [`key_datum_list` | `dict_comprehension`] "}" - key_datum_list: `key_datum` ("," `key_datum`)* [","] - key_datum: `expression` ":" `expression` | "**" `or_expr` + dict_display: "{" [`dict_item_list` | `dict_comprehension`] "}" + dict_item_list: `dict_item` ("," `dict_item`)* [","] + dict_item: `expression` ":" `expression` | "**" `or_expr` dict_comprehension: `expression` ":" `expression` `comp_for` A dictionary display yields a new dictionary object. -If a comma-separated sequence of key/datum pairs is given, they are evaluated +If a comma-separated sequence of dict items is given, they are evaluated from left to right to define the entries of the dictionary: each key object is -used as a key into the dictionary to store the corresponding datum. This means -that you can specify the same key multiple times in the key/datum list, and the +used as a key into the dictionary to store the corresponding value. This means +that you can specify the same key multiple times in the dict item list, and the final dictionary's value for that key will be the last one given. .. index:: @@ -328,7 +328,7 @@ final dictionary's value for that key will be the last one given. A double asterisk ``**`` denotes :dfn:`dictionary unpacking`. Its operand must be a :term:`mapping`. Each mapping item is added to the new dictionary. Later values replace values already set by -earlier key/datum pairs and earlier dictionary unpackings. +earlier dict items and earlier dictionary unpackings. .. versionadded:: 3.5 Unpacking into dictionary displays, originally proposed by :pep:`448`. @@ -344,7 +344,7 @@ in the new dictionary in the order they are produced. Restrictions on the types of the key values are listed earlier in section :ref:`types`. (To summarize, the key type should be :term:`hashable`, which excludes all mutable objects.) Clashes between duplicate keys are not detected; the last -datum (textually rightmost in the display) stored for a given key value +value (textually rightmost in the display) stored for a given key value prevails. .. versionchanged:: 3.8 diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 662a4b643c4378..a9e65be1eda340 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -210,7 +210,7 @@ Assignment of an object to a single target is recursively defined as follows. If the primary is a mapping object (such as a dictionary), the subscript must have a type compatible with the mapping's key type, and the mapping is then - asked to create a key/datum pair which maps the subscript to the assigned + asked to create a key/value pair which maps the subscript to the assigned object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed). From 0355625d94a50f4b816770bad946420d005900b8 Mon Sep 17 00:00:00 2001 From: Jeremy Paige Date: Sun, 2 Jul 2023 22:44:37 -0700 Subject: [PATCH 231/446] Document PYTHONSAFEPATH along side -P (#106122) --- Python/initconfig.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/initconfig.c b/Python/initconfig.c index 147cb370412cd6..787e583262406c 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -49,7 +49,7 @@ Options (and corresponding environment variables):\n\ .pyc extension; also PYTHONOPTIMIZE=x\n\ -OO : do -O changes and also discard docstrings; add .opt-2 before\n\ .pyc extension\n\ --P : don't prepend a potentially unsafe path to sys.path\n\ +-P : don't prepend a potentially unsafe path to sys.path; also PYTHONSAFEPATH\n\ -q : don't print version and copyright messages on interactive startup\n\ -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\ -S : don't imply 'import site' on initialization\n\ @@ -144,7 +144,6 @@ static const char usage_envvars[] = "PYTHONSTARTUP: file executed on interactive startup (no default)\n" "PYTHONPATH : '%lc'-separated list of directories prefixed to the\n" " default module search path. The result is sys.path.\n" -"PYTHONSAFEPATH: don't prepend a potentially unsafe path to sys.path.\n" "PYTHONHOME : alternate directory (or %lc).\n" " The default module search path uses %s.\n" "PYTHONPLATLIBDIR : override sys.platlibdir.\n" @@ -184,6 +183,7 @@ static const char usage_envvars[] = " (-X int_max_str_digits=number)\n" "PYTHONNOUSERSITE : disable user site directory (-s)\n" "PYTHONOPTIMIZE : enable level 1 optimizations (-O)\n" +"PYTHONSAFEPATH : don't prepend a potentially unsafe path to sys.path (-P)\n" "PYTHONUNBUFFERED : disable stdout/stderr buffering (-u)\n" "PYTHONVERBOSE : trace import statements (-v)\n" "PYTHONWARNINGS=arg : warning control (-W arg)\n"; From d65b783b6966d233467a48ef633afb4aff9d5df8 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Mon, 3 Jul 2023 07:56:54 +0100 Subject: [PATCH 232/446] gh-61215: New mock to wait for multi-threaded events to happen (#16094) mock: Add `ThreadingMock` class Add a new class that allows to wait for a call to happen by using `Event` objects. This mock class can be used to test and validate expectations of multithreading code. It uses two attributes for events to distinguish calls with any argument and calls with specific arguments. The calls with specific arguments need a lock to prevent two calls in parallel from creating the same event twice. The timeout is configured at class and constructor level to allow users to set a timeout, we considered passing it as an argument to the function but it could collide with a function parameter. Alternatively we also considered passing it as positional only but from an API caller perspective it was unclear what the first number meant on the function call, think `mock.wait_until_called(1, "arg1", "arg2")`, where 1 is the timeout. Lastly we also considered adding the new attributes to magic mock directly rather than having a custom mock class for multi threading scenarios, but we preferred to have specialised class that can be composed if necessary. Additionally, having added it to `MagicMock` directly would have resulted in `AsyncMock` having this logic, which would not work as expected, since when if user "waits" on a coroutine does not have the same meaning as waiting on a standard call. Co-authored-by: Karthikeyan Singaravelan --- Doc/library/unittest.mock.rst | 47 +++ .../testmock/testthreadingmock.py | 278 ++++++++++++++++++ Lib/unittest/mock.py | 94 ++++++ .../2019-09-13-13-28-10.bpo-17013.NWcgE3.rst | 3 + 4 files changed, 422 insertions(+) create mode 100644 Lib/test/test_unittest/testmock/testthreadingmock.py create mode 100644 Misc/NEWS.d/next/Library/2019-09-13-13-28-10.bpo-17013.NWcgE3.rst diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 6c4d801f69f5a9..756422bd6eab9e 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -205,8 +205,10 @@ The Mock Class import asyncio import inspect import unittest + import threading from unittest.mock import sentinel, DEFAULT, ANY from unittest.mock import patch, call, Mock, MagicMock, PropertyMock, AsyncMock + from unittest.mock import ThreadingMock from unittest.mock import mock_open :class:`Mock` is a flexible mock object intended to replace the use of stubs and @@ -1099,6 +1101,51 @@ object:: [call('foo'), call('bar')] +.. class:: ThreadingMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, *, timeout=UNSET, **kwargs) + + A version of :class:`MagicMock` for multithreading tests. The + :class:`ThreadingMock` object provides extra methods to wait for a call to + be invoked, rather than assert on it immediately. + + The default timeout is specified by the ``timeout`` argument, or if unset by the + :attr:`ThreadingMock.DEFAULT_TIMEOUT` attribute, which defaults to blocking (``None``). + + You can configure the global default timeout by setting :attr:`ThreadingMock.DEFAULT_TIMEOUT`. + + .. method:: wait_until_called(*, timeout=UNSET) + + Waits until the mock is called. + + If a timeout was passed at the creation of the mock or if a timeout + argument is passed to this function, the function raises an + :exc:`AssertionError` if the call is not performed in time. + + >>> mock = ThreadingMock() + >>> thread = threading.Thread(target=mock) + >>> thread.start() + >>> mock.wait_until_called(timeout=1) + >>> thread.join() + + .. method:: wait_until_any_call(*args, **kwargs) + + Waits until the the mock is called with the specified arguments. + + If a timeout was passed at the creation of the mock + the function raises an :exc:`AssertionError` if the call is not performed in time. + + >>> mock = ThreadingMock() + >>> thread = threading.Thread(target=mock, args=("arg1", "arg2",), kwargs={"arg": "thing"}) + >>> thread.start() + >>> mock.wait_until_any_call("arg1", "arg2", arg="thing") + >>> thread.join() + + .. attribute:: DEFAULT_TIMEOUT + + Global default timeout in seconds to create instances of :class:`ThreadingMock`. + + .. versionadded:: 3.13 + + Calling ~~~~~~~ diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py new file mode 100644 index 00000000000000..6219cc58abdc44 --- /dev/null +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -0,0 +1,278 @@ +import time +import unittest +import concurrent.futures + +from unittest.mock import patch, ThreadingMock, call + + +class Something: + def method_1(self): + pass + + def method_2(self): + pass + + +class TestThreadingMock(unittest.TestCase): + def _call_after_delay(self, func, /, *args, **kwargs): + time.sleep(kwargs.pop("delay")) + func(*args, **kwargs) + + def setUp(self): + self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=5) + + def tearDown(self): + self._executor.shutdown() + + def run_async(self, func, /, *args, delay=0, **kwargs): + self._executor.submit( + self._call_after_delay, func, *args, **kwargs, delay=delay + ) + + def _make_mock(self, *args, **kwargs): + return ThreadingMock(*args, **kwargs) + + def test_spec(self): + waitable_mock = self._make_mock(spec=Something) + + with patch(f"{__name__}.Something", waitable_mock) as m: + something = m() + + self.assertIsInstance(something.method_1, ThreadingMock) + self.assertIsInstance(something.method_1().method_2(), ThreadingMock) + + with self.assertRaises(AttributeError): + m.test + + def test_side_effect(self): + waitable_mock = self._make_mock() + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + something.method_1.side_effect = [1] + + self.assertEqual(something.method_1(), 1) + + def test_instance_check(self): + waitable_mock = self._make_mock() + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + + self.assertIsInstance(something.method_1, ThreadingMock) + self.assertIsInstance(something.method_1().method_2(), ThreadingMock) + + def test_dynamic_child_mocks_are_threading_mocks(self): + waitable_mock = self._make_mock() + self.assertIsInstance(waitable_mock.child, ThreadingMock) + + def test_dynamic_child_mocks_inherit_timeout(self): + mock1 = self._make_mock() + self.assertIs(mock1._mock_wait_timeout, None) + mock2 = self._make_mock(timeout=2) + self.assertEqual(mock2._mock_wait_timeout, 2) + mock3 = self._make_mock(timeout=3) + self.assertEqual(mock3._mock_wait_timeout, 3) + + self.assertIs(mock1.child._mock_wait_timeout, None) + self.assertEqual(mock2.child._mock_wait_timeout, 2) + self.assertEqual(mock3.child._mock_wait_timeout, 3) + + self.assertEqual(mock2.really().__mul__().complex._mock_wait_timeout, 2) + + def test_no_name_clash(self): + waitable_mock = self._make_mock() + waitable_mock._event = "myevent" + waitable_mock.event = "myevent" + waitable_mock.timeout = "mytimeout" + waitable_mock("works") + waitable_mock.wait_until_called() + waitable_mock.wait_until_any_call("works") + + def test_wait_success(self): + waitable_mock = self._make_mock(spec=Something) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, delay=0.01) + something.method_1.wait_until_called() + something.method_1.wait_until_any_call() + something.method_1.assert_called() + + def test_wait_success_with_instance_timeout(self): + waitable_mock = self._make_mock(timeout=1) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, delay=0.01) + something.method_1.wait_until_called() + something.method_1.wait_until_any_call() + something.method_1.assert_called() + + def test_wait_failed_with_instance_timeout(self): + waitable_mock = self._make_mock(timeout=0.01) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, delay=0.5) + self.assertRaises(AssertionError, waitable_mock.method_1.wait_until_called) + self.assertRaises( + AssertionError, waitable_mock.method_1.wait_until_any_call + ) + + def test_wait_success_with_timeout_override(self): + waitable_mock = self._make_mock(timeout=0.01) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, delay=0.05) + something.method_1.wait_until_called(timeout=1) + + def test_wait_failed_with_timeout_override(self): + waitable_mock = self._make_mock(timeout=1) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, delay=0.1) + with self.assertRaises(AssertionError): + something.method_1.wait_until_called(timeout=0.05) + with self.assertRaises(AssertionError): + something.method_1.wait_until_any_call(timeout=0.05) + + def test_wait_success_called_before(self): + waitable_mock = self._make_mock() + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + something.method_1() + something.method_1.wait_until_called() + something.method_1.wait_until_any_call() + something.method_1.assert_called() + + def test_wait_magic_method(self): + waitable_mock = self._make_mock() + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1.__str__, delay=0.01) + something.method_1.__str__.wait_until_called() + something.method_1.__str__.assert_called() + + def test_wait_until_any_call_positional(self): + waitable_mock = self._make_mock(spec=Something) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, 1, delay=0.1) + self.run_async(something.method_1, 2, delay=0.2) + self.run_async(something.method_1, 3, delay=0.3) + self.assertNotIn(call(1), something.method_1.mock_calls) + + something.method_1.wait_until_any_call(1) + something.method_1.assert_called_with(1) + self.assertNotIn(call(2), something.method_1.mock_calls) + self.assertNotIn(call(3), something.method_1.mock_calls) + + something.method_1.wait_until_any_call(3) + self.assertIn(call(2), something.method_1.mock_calls) + something.method_1.wait_until_any_call(2) + + def test_wait_until_any_call_keywords(self): + waitable_mock = self._make_mock(spec=Something) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + self.run_async(something.method_1, a=1, delay=0.1) + self.run_async(something.method_1, b=2, delay=0.2) + self.run_async(something.method_1, c=3, delay=0.3) + self.assertNotIn(call(a=1), something.method_1.mock_calls) + + something.method_1.wait_until_any_call(a=1) + something.method_1.assert_called_with(a=1) + self.assertNotIn(call(b=2), something.method_1.mock_calls) + self.assertNotIn(call(c=3), something.method_1.mock_calls) + + something.method_1.wait_until_any_call(c=3) + self.assertIn(call(b=2), something.method_1.mock_calls) + something.method_1.wait_until_any_call(b=2) + + def test_wait_until_any_call_no_argument_fails_when_called_with_arg(self): + waitable_mock = self._make_mock(timeout=0.01) + + with patch(f"{__name__}.Something", waitable_mock): + something = Something() + something.method_1(1) + + something.method_1.assert_called_with(1) + with self.assertRaises(AssertionError): + something.method_1.wait_until_any_call() + + something.method_1() + something.method_1.wait_until_any_call() + + def test_wait_until_any_call_global_default(self): + with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): + ThreadingMock.DEFAULT_TIMEOUT = 0.01 + m = self._make_mock() + with self.assertRaises(AssertionError): + m.wait_until_any_call() + with self.assertRaises(AssertionError): + m.wait_until_called() + + m() + m.wait_until_any_call() + assert ThreadingMock.DEFAULT_TIMEOUT != 0.01 + + def test_wait_until_any_call_change_global_and_override(self): + with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): + ThreadingMock.DEFAULT_TIMEOUT = 0.01 + + m1 = self._make_mock() + self.run_async(m1, delay=0.1) + with self.assertRaises(AssertionError): + m1.wait_until_called() + + m2 = self._make_mock(timeout=1) + self.run_async(m2, delay=0.1) + m2.wait_until_called() + + m3 = self._make_mock() + self.run_async(m3, delay=0.1) + m3.wait_until_called(timeout=1) + + m4 = self._make_mock() + self.run_async(m4, delay=0.1) + m4.wait_until_called(timeout=None) + + m5 = self._make_mock(timeout=None) + self.run_async(m5, delay=0.1) + m5.wait_until_called() + + assert ThreadingMock.DEFAULT_TIMEOUT != 0.01 + + def test_reset_mock_resets_wait(self): + m = self._make_mock(timeout=0.01) + + with self.assertRaises(AssertionError): + m.wait_until_called() + with self.assertRaises(AssertionError): + m.wait_until_any_call() + m() + m.wait_until_called() + m.wait_until_any_call() + m.assert_called_once() + + m.reset_mock() + + with self.assertRaises(AssertionError): + m.wait_until_called() + with self.assertRaises(AssertionError): + m.wait_until_any_call() + m() + m.wait_until_called() + m.wait_until_any_call() + m.assert_called_once() + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index f10f9b04a5ab18..b542a9a2c51a9f 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -14,6 +14,7 @@ 'call', 'create_autospec', 'AsyncMock', + 'ThreadingMock', 'FILTER_DIR', 'NonCallableMock', 'NonCallableMagicMock', @@ -32,6 +33,7 @@ import builtins import pkgutil from asyncio import iscoroutinefunction +import threading from types import CodeType, ModuleType, MethodType from unittest.util import safe_repr from functools import wraps, partial @@ -3003,6 +3005,98 @@ def __set__(self, obj, val): self(val) +_timeout_unset = sentinel.TIMEOUT_UNSET + +class ThreadingMixin(Base): + + DEFAULT_TIMEOUT = None + + def _get_child_mock(self, /, **kw): + if "timeout" in kw: + kw["timeout"] = kw.pop("timeout") + elif isinstance(kw.get("parent"), ThreadingMixin): + kw["timeout"] = kw["parent"]._mock_wait_timeout + elif isinstance(kw.get("_new_parent"), ThreadingMixin): + kw["timeout"] = kw["_new_parent"]._mock_wait_timeout + return super()._get_child_mock(**kw) + + def __init__(self, *args, timeout=_timeout_unset, **kwargs): + super().__init__(*args, **kwargs) + if timeout is _timeout_unset: + timeout = self.DEFAULT_TIMEOUT + self.__dict__["_mock_event"] = threading.Event() # Event for any call + self.__dict__["_mock_calls_events"] = [] # Events for each of the calls + self.__dict__["_mock_calls_events_lock"] = threading.Lock() + self.__dict__["_mock_wait_timeout"] = timeout + + def reset_mock(self, /, *args, **kwargs): + """ + See :func:`.Mock.reset_mock()` + """ + super().reset_mock(*args, **kwargs) + self.__dict__["_mock_event"] = threading.Event() + self.__dict__["_mock_calls_events"] = [] + + def __get_event(self, expected_args, expected_kwargs): + with self._mock_calls_events_lock: + for args, kwargs, event in self._mock_calls_events: + if (args, kwargs) == (expected_args, expected_kwargs): + return event + new_event = threading.Event() + self._mock_calls_events.append((expected_args, expected_kwargs, new_event)) + return new_event + + def _mock_call(self, *args, **kwargs): + ret_value = super()._mock_call(*args, **kwargs) + + call_event = self.__get_event(args, kwargs) + call_event.set() + + self._mock_event.set() + + return ret_value + + def wait_until_called(self, *, timeout=_timeout_unset): + """Wait until the mock object is called. + + `timeout` - time to wait for in seconds, waits forever otherwise. + Defaults to the constructor provided timeout. + Use None to block undefinetively. + """ + if timeout is _timeout_unset: + timeout = self._mock_wait_timeout + if not self._mock_event.wait(timeout=timeout): + msg = (f"{self._mock_name or 'mock'} was not called before" + f" timeout({timeout}).") + raise AssertionError(msg) + + def wait_until_any_call(self, *args, **kwargs): + """Wait until the mock object is called with given args. + + Waits for the timeout in seconds provided in the constructor. + """ + event = self.__get_event(args, kwargs) + if not event.wait(timeout=self._mock_wait_timeout): + expected_string = self._format_mock_call_signature(args, kwargs) + raise AssertionError(f'{expected_string} call not found') + + +class ThreadingMock(ThreadingMixin, MagicMixin, Mock): + """ + A mock that can be used to wait until on calls happening + in a different thread. + + The constructor can take a `timeout` argument which + controls the timeout in seconds for all `wait` calls of the mock. + + You can change the default timeout of all instances via the + `ThreadingMock.DEFAULT_TIMEOUT` attribute. + + If no timeout is set, it will block undefinetively. + """ + pass + + def seal(mock): """Disable the automatic generation of child mocks. diff --git a/Misc/NEWS.d/next/Library/2019-09-13-13-28-10.bpo-17013.NWcgE3.rst b/Misc/NEWS.d/next/Library/2019-09-13-13-28-10.bpo-17013.NWcgE3.rst new file mode 100644 index 00000000000000..ac746c45fa9ea8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-13-13-28-10.bpo-17013.NWcgE3.rst @@ -0,0 +1,3 @@ +Add ``ThreadingMock`` to :mod:`unittest.mock` that can be used to create +Mock objects that can wait until they are called. Patch by Karthikeyan +Singaravelan and Mario Corchero. From 5ccbbe5bb9a659fa8f2fe551428c84cc14015f44 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 3 Jul 2023 10:23:43 +0200 Subject: [PATCH 233/446] gh-106320: Move _PyUnicodeWriter to the internal C API (#106342) Move also _PyUnicode_FormatAdvancedWriter(). CJK codecs and multibytecodec.c now define the Py_BUILD_CORE_MODULE macro. --- Include/cpython/unicodeobject.h | 139 ----------------- Include/internal/pycore_complexobject.h | 2 + Include/internal/pycore_floatobject.h | 2 + Include/internal/pycore_unicodeobject.h | 145 +++++++++++++++++- Modules/cjkcodecs/cjkcodecs.h | 4 + Modules/cjkcodecs/multibytecodec.c | 4 + Modules/cjkcodecs/multibytecodec.h | 2 + Tools/c-analyzer/c_parser/preprocessor/gcc.py | 12 +- 8 files changed, 166 insertions(+), 144 deletions(-) diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index dee8b27d3d97de..c5892a80d2c54d 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -480,131 +480,6 @@ PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( Py_ssize_t start, Py_ssize_t end); -/* --- _PyUnicodeWriter API ----------------------------------------------- */ - -typedef struct { - PyObject *buffer; - void *data; - int kind; - Py_UCS4 maxchar; - Py_ssize_t size; - Py_ssize_t pos; - - /* minimum number of allocated characters (default: 0) */ - Py_ssize_t min_length; - - /* minimum character (default: 127, ASCII) */ - Py_UCS4 min_char; - - /* If non-zero, overallocate the buffer (default: 0). */ - unsigned char overallocate; - - /* If readonly is 1, buffer is a shared string (cannot be modified) - and size is set to 0. */ - unsigned char readonly; -} _PyUnicodeWriter ; - -/* Initialize a Unicode writer. - * - * By default, the minimum buffer size is 0 character and overallocation is - * disabled. Set min_length, min_char and overallocate attributes to control - * the allocation of the buffer. */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Init(_PyUnicodeWriter *writer); - -/* Prepare the buffer to write 'length' characters - with the specified maximum character. - - Return 0 on success, raise an exception and return -1 on error. */ -#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \ - (((MAXCHAR) <= (WRITER)->maxchar \ - && (LENGTH) <= (WRITER)->size - (WRITER)->pos) \ - ? 0 \ - : (((LENGTH) == 0) \ - ? 0 \ - : _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR)))) - -/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro - instead. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, - Py_ssize_t length, Py_UCS4 maxchar); - -/* Prepare the buffer to have at least the kind KIND. - For example, kind=PyUnicode_2BYTE_KIND ensures that the writer will - support characters in range U+000-U+FFFF. - - Return 0 on success, raise an exception and return -1 on error. */ -#define _PyUnicodeWriter_PrepareKind(WRITER, KIND) \ - ((KIND) <= (WRITER)->kind \ - ? 0 \ - : _PyUnicodeWriter_PrepareKindInternal((WRITER), (KIND))) - -/* Don't call this function directly, use the _PyUnicodeWriter_PrepareKind() - macro instead. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer, - int kind); - -/* Append a Unicode character. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, - Py_UCS4 ch - ); - -/* Append a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, - PyObject *str /* Unicode string */ - ); - -/* Append a substring of a Unicode string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, - PyObject *str, /* Unicode string */ - Py_ssize_t start, - Py_ssize_t end - ); - -/* Append an ASCII-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, - const char *str, /* ASCII-encoded byte string */ - Py_ssize_t len /* number of bytes, or -1 if unknown */ - ); - -/* Append a latin1-encoded byte string. - Return 0 on success, raise an exception and return -1 on error. */ -PyAPI_FUNC(int) -_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, - const char *str, /* latin1-encoded byte string */ - Py_ssize_t len /* length in bytes */ - ); - -/* Get the value of the writer as a Unicode string. Clear the - buffer of the writer. Raise an exception and return NULL - on error. */ -PyAPI_FUNC(PyObject *) -_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) -_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); - - -/* Format the object based on the format_spec, as defined in PEP 3101 - (Advanced String Formatting). */ -PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( - _PyUnicodeWriter *writer, - PyObject *obj, - PyObject *format_spec, - Py_ssize_t start, - Py_ssize_t end); - /* --- Manage the default encoding ---------------------------------------- */ /* Returns a pointer to the default encoding (UTF-8) of the @@ -774,20 +649,6 @@ PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( PyObject *sepobj ); -/* Using explicit passed-in values, insert the thousands grouping - into the string pointed to by buffer. For the argument descriptions, - see Objects/stringlib/localeutil.h */ -PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( - _PyUnicodeWriter *writer, - Py_ssize_t n_buffer, - PyObject *digits, - Py_ssize_t d_pos, - Py_ssize_t n_digits, - Py_ssize_t min_width, - const char *grouping, - PyObject *thousands_sep, - Py_UCS4 *maxchar); - /* === Characters Type APIs =============================================== */ /* These should not be used directly. Use the Py_UNICODE_IS* and diff --git a/Include/internal/pycore_complexobject.h b/Include/internal/pycore_complexobject.h index fb344b7bb79bd8..7843c0a008ebb6 100644 --- a/Include/internal/pycore_complexobject.h +++ b/Include/internal/pycore_complexobject.h @@ -8,6 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_unicodeobject.h" // _PyUnicodeWriter + /* Operations on complex numbers from complexmodule.c */ PyAPI_FUNC(Py_complex) _Py_c_sum(Py_complex, Py_complex); diff --git a/Include/internal/pycore_floatobject.h b/Include/internal/pycore_floatobject.h index 27c63bc87f3ee3..6abba04033d281 100644 --- a/Include/internal/pycore_floatobject.h +++ b/Include/internal/pycore_floatobject.h @@ -9,6 +9,8 @@ extern "C" { #endif +#include "pycore_unicodeobject.h" // _PyUnicodeWriter + /* runtime lifecycle */ extern void _PyFloat_InitState(PyInterpreterState *); diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 1bb0f366e78163..a8c7f1957f3600 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -14,7 +14,148 @@ extern "C" { void _PyUnicode_ExactDealloc(PyObject *op); Py_ssize_t _PyUnicode_InternedSize(void); -/* runtime lifecycle */ +/* --- _PyUnicodeWriter API ----------------------------------------------- */ + +typedef struct { + PyObject *buffer; + void *data; + int kind; + Py_UCS4 maxchar; + Py_ssize_t size; + Py_ssize_t pos; + + /* minimum number of allocated characters (default: 0) */ + Py_ssize_t min_length; + + /* minimum character (default: 127, ASCII) */ + Py_UCS4 min_char; + + /* If non-zero, overallocate the buffer (default: 0). */ + unsigned char overallocate; + + /* If readonly is 1, buffer is a shared string (cannot be modified) + and size is set to 0. */ + unsigned char readonly; +} _PyUnicodeWriter ; + +/* Initialize a Unicode writer. + * + * By default, the minimum buffer size is 0 character and overallocation is + * disabled. Set min_length, min_char and overallocate attributes to control + * the allocation of the buffer. */ +PyAPI_FUNC(void) +_PyUnicodeWriter_Init(_PyUnicodeWriter *writer); + +/* Prepare the buffer to write 'length' characters + with the specified maximum character. + + Return 0 on success, raise an exception and return -1 on error. */ +#define _PyUnicodeWriter_Prepare(WRITER, LENGTH, MAXCHAR) \ + (((MAXCHAR) <= (WRITER)->maxchar \ + && (LENGTH) <= (WRITER)->size - (WRITER)->pos) \ + ? 0 \ + : (((LENGTH) == 0) \ + ? 0 \ + : _PyUnicodeWriter_PrepareInternal((WRITER), (LENGTH), (MAXCHAR)))) + +/* Don't call this function directly, use the _PyUnicodeWriter_Prepare() macro + instead. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_PrepareInternal(_PyUnicodeWriter *writer, + Py_ssize_t length, Py_UCS4 maxchar); + +/* Prepare the buffer to have at least the kind KIND. + For example, kind=PyUnicode_2BYTE_KIND ensures that the writer will + support characters in range U+000-U+FFFF. + + Return 0 on success, raise an exception and return -1 on error. */ +#define _PyUnicodeWriter_PrepareKind(WRITER, KIND) \ + ((KIND) <= (WRITER)->kind \ + ? 0 \ + : _PyUnicodeWriter_PrepareKindInternal((WRITER), (KIND))) + +/* Don't call this function directly, use the _PyUnicodeWriter_PrepareKind() + macro instead. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_PrepareKindInternal(_PyUnicodeWriter *writer, + int kind); + +/* Append a Unicode character. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteChar(_PyUnicodeWriter *writer, + Py_UCS4 ch + ); + +/* Append a Unicode string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteStr(_PyUnicodeWriter *writer, + PyObject *str /* Unicode string */ + ); + +/* Append a substring of a Unicode string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, + PyObject *str, /* Unicode string */ + Py_ssize_t start, + Py_ssize_t end + ); + +/* Append an ASCII-encoded byte string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteASCIIString(_PyUnicodeWriter *writer, + const char *str, /* ASCII-encoded byte string */ + Py_ssize_t len /* number of bytes, or -1 if unknown */ + ); + +/* Append a latin1-encoded byte string. + Return 0 on success, raise an exception and return -1 on error. */ +PyAPI_FUNC(int) +_PyUnicodeWriter_WriteLatin1String(_PyUnicodeWriter *writer, + const char *str, /* latin1-encoded byte string */ + Py_ssize_t len /* length in bytes */ + ); + +/* Get the value of the writer as a Unicode string. Clear the + buffer of the writer. Raise an exception and return NULL + on error. */ +PyAPI_FUNC(PyObject *) +_PyUnicodeWriter_Finish(_PyUnicodeWriter *writer); + +/* Deallocate memory of a writer (clear its internal buffer). */ +PyAPI_FUNC(void) +_PyUnicodeWriter_Dealloc(_PyUnicodeWriter *writer); + + +/* Format the object based on the format_spec, as defined in PEP 3101 + (Advanced String Formatting). */ +PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( + _PyUnicodeWriter *writer, + PyObject *obj, + PyObject *format_spec, + Py_ssize_t start, + Py_ssize_t end); + +/* --- Methods & Slots ---------------------------------------------------- */ + +/* Using explicit passed-in values, insert the thousands grouping + into the string pointed to by buffer. For the argument descriptions, + see Objects/stringlib/localeutil.h */ +PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( + _PyUnicodeWriter *writer, + Py_ssize_t n_buffer, + PyObject *digits, + Py_ssize_t d_pos, + Py_ssize_t n_digits, + Py_ssize_t min_width, + const char *grouping, + PyObject *thousands_sep, + Py_UCS4 *maxchar); + +/* --- Runtime lifecycle -------------------------------------------------- */ extern void _PyUnicode_InitState(PyInterpreterState *); extern PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *); @@ -24,7 +165,7 @@ extern void _PyUnicode_FiniTypes(PyInterpreterState *); extern PyTypeObject _PyUnicodeASCIIIter_Type; -/* other API */ +/* --- Other API ---------------------------------------------------------- */ struct _Py_unicode_runtime_ids { PyThread_type_lock lock; diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index 48cdcfb3ad3087..97290aac3ba439 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -7,6 +7,10 @@ #ifndef _CJKCODECS_H_ #define _CJKCODECS_H_ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" #include "multibytecodec.h" diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index cf437d09f1fe8d..3febd1a832f9cc 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -4,6 +4,10 @@ * Written by Hye-Shik Chang */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" #include "structmember.h" // PyMemberDef #include "multibytecodec.h" diff --git a/Modules/cjkcodecs/multibytecodec.h b/Modules/cjkcodecs/multibytecodec.h index f59362205d26fc..5b85e2e3de316d 100644 --- a/Modules/cjkcodecs/multibytecodec.h +++ b/Modules/cjkcodecs/multibytecodec.h @@ -10,6 +10,8 @@ extern "C" { #endif +#include "pycore_unicodeobject.h" // _PyUnicodeWriter + #ifdef uint16_t typedef uint16_t ucs2_t, DBCHAR; #else diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 0929f7111eac92..415a2ba63dfe68 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -3,6 +3,14 @@ from . import common as _common +# Modules/socketmodule.h uses pycore_time.h which needs the Py_BUILD_CORE +# macro. Usually it's defined by the C file which includes it. +# Other header files have a similar issue. +NEED_BUILD_CORE = { + 'cjkcodecs.h', + 'multibytecodec.h', + 'socketmodule.h', +} TOOL = 'gcc' @@ -62,9 +70,7 @@ def preprocess(filename, filename = _normpath(filename, cwd) postargs = POST_ARGS - if os.path.basename(filename) == 'socketmodule.h': - # Modules/socketmodule.h uses pycore_time.h which needs Py_BUILD_CORE. - # Usually it's defined by the C file which includes it. + if os.path.basename(filename) in NEED_BUILD_CORE: postargs += ('-DPy_BUILD_CORE=1',) text = _common.preprocess( From 35963da40fb7bc93c55d94caf58ff9e268df951d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 3 Jul 2023 11:39:11 +0200 Subject: [PATCH 234/446] gh-106320: Create pycore_modsupport.h header file (#106355) Remove the following functions from the C API, move them to the internal C API: add a new pycore_modsupport.h internal header file: * PyModule_CreateInitialized() * _PyArg_NoKwnames() * _Py_VaBuildStack() No longer export these functions. --- Include/cpython/modsupport.h | 12 ------------ Include/internal/pycore_modsupport.h | 29 ++++++++++++++++++++++++++++ Makefile.pre.in | 1 + Modules/_operator.c | 4 +++- Objects/boolobject.c | 5 +++-- Objects/call.c | 1 + Objects/enumobject.c | 1 + Objects/floatobject.c | 1 + Objects/listobject.c | 1 + Objects/moduleobject.c | 3 ++- Objects/rangeobject.c | 3 ++- Objects/setobject.c | 1 + Objects/tupleobject.c | 1 + Objects/typeobject.c | 1 + Objects/weakrefobject.c | 1 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ Python/bltinmodule.c | 3 ++- Python/instrumentation.c | 1 + Python/sysmodule.c | 1 + 20 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 Include/internal/pycore_modsupport.h diff --git a/Include/cpython/modsupport.h b/Include/cpython/modsupport.h index a5d95d15440df1..376336b13dcf8a 100644 --- a/Include/cpython/modsupport.h +++ b/Include/cpython/modsupport.h @@ -11,12 +11,9 @@ PyAPI_FUNC(int) _PyArg_UnpackStack( ...); PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kwargs); -PyAPI_FUNC(int) _PyArg_NoKwnames(const char *funcname, PyObject *kwnames); PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args); #define _PyArg_NoKeywords(funcname, kwargs) \ ((kwargs) == NULL || _PyArg_NoKeywords((funcname), (kwargs))) -#define _PyArg_NoKwnames(funcname, kwnames) \ - ((kwnames) == NULL || _PyArg_NoKwnames((funcname), (kwnames))) #define _PyArg_NoPositional(funcname, args) \ ((args) == NULL || _PyArg_NoPositional((funcname), (args))) @@ -29,13 +26,6 @@ PyAPI_FUNC(int) _PyArg_CheckPositional(const char *, Py_ssize_t, ((!_Py_ANY_VARARGS(max) && (min) <= (nargs) && (nargs) <= (max)) \ || _PyArg_CheckPositional((funcname), (nargs), (min), (max))) -PyAPI_FUNC(PyObject **) _Py_VaBuildStack( - PyObject **small_stack, - Py_ssize_t small_stack_len, - const char *format, - va_list va, - Py_ssize_t *p_nargs); - typedef struct _PyArg_Parser { int initialized; const char *format; @@ -83,5 +73,3 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywordsWithVararg( (minpos) <= (nargs) && (nargs) <= (maxpos) && (args) != NULL) ? (args) : \ _PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \ (minpos), (maxpos), (minkw), (buf))) - -PyAPI_FUNC(PyObject *) _PyModule_CreateInitialized(PyModuleDef*, int apiver); diff --git a/Include/internal/pycore_modsupport.h b/Include/internal/pycore_modsupport.h new file mode 100644 index 00000000000000..e577c6ba856b77 --- /dev/null +++ b/Include/internal/pycore_modsupport.h @@ -0,0 +1,29 @@ +#ifndef Py_INTERNAL_MODSUPPORT_H +#define Py_INTERNAL_MODSUPPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + + +extern int _PyArg_NoKwnames(const char *funcname, PyObject *kwnames); +#define _PyArg_NoKwnames(funcname, kwnames) \ + ((kwnames) == NULL || _PyArg_NoKwnames((funcname), (kwnames))) + +extern PyObject ** _Py_VaBuildStack( + PyObject **small_stack, + Py_ssize_t small_stack_len, + const char *format, + va_list va, + Py_ssize_t *p_nargs); + +extern PyObject* _PyModule_CreateInitialized(PyModuleDef*, int apiver); + +#ifdef __cplusplus +} +#endif +#endif // !Py_INTERNAL_MODSUPPORT_H + diff --git a/Makefile.pre.in b/Makefile.pre.in index 7560d17e3796f0..dcb3b5eb06a1e9 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1761,6 +1761,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_intrinsics.h \ $(srcdir)/Include/internal/pycore_list.h \ $(srcdir)/Include/internal/pycore_long.h \ + $(srcdir)/Include/internal/pycore_modsupport.h \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ $(srcdir)/Include/internal/pycore_object.h \ diff --git a/Modules/_operator.c b/Modules/_operator.c index 153e9e9e2f92c4..108f45fb6dad93 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1,7 +1,9 @@ #include "Python.h" +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_moduleobject.h" // _PyModule_GetState() -#include "structmember.h" // PyMemberDef #include "pycore_runtime.h" // _Py_ID() + +#include "structmember.h" // PyMemberDef #include "clinic/_operator.c.h" typedef struct { diff --git a/Objects/boolobject.c b/Objects/boolobject.c index f43e26f3f24e77..bbb187cb7121e7 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -1,8 +1,9 @@ /* Boolean type, a subtype of int */ #include "Python.h" -#include "pycore_object.h" // _Py_FatalRefcountError() -#include "pycore_long.h" // FALSE_TAG TRUE_TAG +#include "pycore_long.h" // FALSE_TAG TRUE_TAG +#include "pycore_modsupport.h" // _PyArg_NoKwnames() +#include "pycore_object.h" // _Py_FatalRefcountError() #include "pycore_runtime.h" // _Py_ID() #include diff --git a/Objects/call.c b/Objects/call.c index 16c41ffe1d09b5..5045c0dc92843b 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -2,6 +2,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgsTstate() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_dict.h" // _PyDict_FromItems() +#include "pycore_modsupport.h" // _Py_VaBuildStack() #include "pycore_object.h" // _PyCFunctionWithKeywords_TrampolineCall() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() diff --git a/Objects/enumobject.c b/Objects/enumobject.c index c9d90584c26b7d..556666779d8522 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetOne() +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "clinic/enumobject.c.h" diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 83a263c0d9c67e..fa55481f09dec0 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -9,6 +9,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_interp.h" // _PyInterpreterState.float_state #include "pycore_long.h" // _PyLong_GetOne() +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_Init() #include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR #include "pycore_pystate.h" // _PyInterpreterState_GET() diff --git a/Objects/listobject.c b/Objects/listobject.c index f1f324f7439b43..98fa08962b6aad 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -5,6 +5,7 @@ #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_state, _PyListIterObject #include "pycore_long.h" // _PyLong_DigitCount +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromArray() #include diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index bda25c881845ce..d4fccae65244c5 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -5,8 +5,9 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyType_AllocNoTrack -#include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_moduleobject.h" // _PyModule_GetDef() +#include "pycore_modsupport.h" // _PyModule_CreateInitialized() +#include "pycore_pystate.h" // _PyInterpreterState_GET() #include "structmember.h" // PyMemberDef diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index beb86b9623bdbc..6dc41d71287cab 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -2,8 +2,9 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_range.h" #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_modsupport.h" // _PyArg_NoKwnames() +#include "pycore_range.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "structmember.h" // PyMemberDef diff --git a/Objects/setobject.c b/Objects/setobject.c index 58f0ae73c0c403..4ac541b9509752 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -32,6 +32,7 @@ */ #include "Python.h" +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include // offsetof() diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 991edcc86677de..e85af2b75e4738 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -5,6 +5,7 @@ #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GC_TRACK(), _Py_FatalRefcountError() /*[clinic input] diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3d3a63a75bd2fb..87519efef081c3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8,6 +8,7 @@ #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() #include "pycore_pyerrors.h" // _PyErr_Occurred() diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index f3f6c86637e9de..bac3e79bb7c250 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -1,4 +1,5 @@ #include "Python.h" +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR() #include "pycore_weakref.h" // _PyWeakref_GET_REF() #include "structmember.h" // PyMemberDef diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 79ce2d3d14017e..760962e4c4b6a9 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -241,6 +241,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index d47a22909e1e3a..aaebe1908e30da 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -627,6 +627,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 68fe315338a54d..9fe0067daa678c 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -4,13 +4,14 @@ #include #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_ceval.h" // _PyEval_Vector() #include "pycore_compile.h" // _PyAST_Compile() #include "pycore_long.h" // _PyLong_CompactValue +#include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_tuple.h" // _PyTuple_FromArray() -#include "pycore_ceval.h" // _PyEval_Vector() #include "clinic/bltinmodule.c.h" diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 03d7d2f215af7c..e29748f0ad9872 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -3,6 +3,7 @@ #include "pycore_frame.h" #include "pycore_interp.h" #include "pycore_long.h" +#include "pycore_modsupport.h" // _PyModule_CreateInitialized() #include "pycore_namespace.h" #include "pycore_object.h" #include "pycore_opcode.h" diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 56d771f70ef538..0ac6edc5a16f88 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -20,6 +20,7 @@ Data members: #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_long.h" // _PY_LONG_MAX_STR_DIGITS_THRESHOLD +#include "pycore_modsupport.h" // _PyModule_CreateInitialized() #include "pycore_namespace.h" // _PyNamespace_New() #include "pycore_object.h" // _PyObject_IS_GC() #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() From 18fedd04a7b4d54b5eb7a34a1e1c9ca42219f882 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 12:06:54 +0200 Subject: [PATCH 235/446] gh-104050: Annotate Argument Clinic DSLParser attributes (#106357) --- Tools/clinic/clinic.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 27d3d572868883..125604bff97f7c 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4293,6 +4293,19 @@ def dedent(self, line): StateKeeper = Callable[[str | None], None] class DSLParser: + function: Function | None + state: StateKeeper + keyword_only: bool + positional_only: bool + group: int + parameter_state: int + seen_positional_with_default: bool + indent: IndentStack + kind: str + coexist: bool + parameter_continuation: str + preserve_output: bool + def __init__(self, clinic: Clinic) -> None: self.clinic = clinic @@ -4312,7 +4325,7 @@ def __init__(self, clinic: Clinic) -> None: def reset(self) -> None: self.function = None - self.state: StateKeeper = self.state_dsl_start + self.state = self.state_dsl_start self.parameter_indent = None self.keyword_only = False self.positional_only = False From c5afc97fc2f149758f597c21f65b4a1c770bb827 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 3 Jul 2023 12:48:50 +0200 Subject: [PATCH 236/446] gh-106320: Remove private _PyErr C API functions (#106356) Remove private _PyErr C API functions: move them to the internal C API (pycore_pyerrors.h). --- Include/cpython/pyerrors.h | 42 -------------------------- Include/internal/pycore_pyerrors.h | 48 ++++++++++++++++++++++++++++++ Modules/_io/bufferedio.c | 1 + Modules/_sqlite/cursor.c | 6 ++++ Objects/moduleobject.c | 5 ++-- Objects/obmalloc.c | 4 +-- Objects/unicodeobject.c | 1 + Parser/pegen_errors.c | 1 + Python/importdl.c | 1 + 9 files changed, 63 insertions(+), 46 deletions(-) diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 156665cbdb1ba4..5c128211bd525a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -91,31 +91,14 @@ typedef PyOSErrorObject PyWindowsErrorObject; /* Error handling definitions */ PyAPI_FUNC(void) _PyErr_SetKeyError(PyObject *); -PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); -PyAPI_FUNC(PyObject*) _PyErr_GetHandledException(PyThreadState *); -PyAPI_FUNC(void) _PyErr_SetHandledException(PyThreadState *, PyObject *); -PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); /* Context manipulation (PEP 3134) */ Py_DEPRECATED(3.12) PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *); -/* Like PyErr_Format(), but saves current exception as __context__ and - __cause__. - */ -PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( - PyObject *exception, - const char *format, /* ASCII-encoded string */ - ... - ); - /* In exceptions.c */ -PyAPI_FUNC(int) _PyException_AddNote( - PyObject *exc, - PyObject *note); - PyAPI_FUNC(PyObject*) PyUnstable_Exc_PrepReraiseStar( PyObject *orig, PyObject *excs); @@ -123,7 +106,6 @@ PyAPI_FUNC(PyObject*) PyUnstable_Exc_PrepReraiseStar( /* In signalmodule.c */ int PySignal_SetWakeupFd(int fd); -PyAPI_FUNC(int) _PyErr_CheckSignals(void); /* Support for adding program text to SyntaxErrors */ @@ -143,18 +125,6 @@ PyAPI_FUNC(PyObject *) PyErr_ProgramTextObject( PyObject *filename, int lineno); -PyAPI_FUNC(PyObject *) _PyErr_ProgramDecodedTextObject( - PyObject *filename, - int lineno, - const char* encoding); - -PyAPI_FUNC(PyObject *) _PyUnicodeTranslateError_Create( - PyObject *object, - Py_ssize_t start, - Py_ssize_t end, - const char *reason /* UTF-8 encoded string */ - ); - PyAPI_FUNC(void) _PyErr_WriteUnraisableMsg( const char *err_msg, PyObject *obj); @@ -163,16 +133,4 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFunc( const char *func, const char *message); -PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFormat( - const char *func, - const char *format, - ...); - -extern PyObject *_PyErr_SetImportErrorWithNameFrom( - PyObject *, - PyObject *, - PyObject *, - PyObject *); - - #define Py_FatalError(message) _Py_FatalErrorFunc(__func__, (message)) diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h index d75bef0c3b5d8f..e3ba4b75e3cfc3 100644 --- a/Include/internal/pycore_pyerrors.h +++ b/Include/internal/pycore_pyerrors.h @@ -9,6 +9,54 @@ extern "C" { #endif +/* Error handling definitions */ + +PyAPI_FUNC(_PyErr_StackItem*) _PyErr_GetTopmostException(PyThreadState *tstate); +PyAPI_FUNC(PyObject*) _PyErr_GetHandledException(PyThreadState *); +PyAPI_FUNC(void) _PyErr_SetHandledException(PyThreadState *, PyObject *); +PyAPI_FUNC(void) _PyErr_GetExcInfo(PyThreadState *, PyObject **, PyObject **, PyObject **); + +/* Like PyErr_Format(), but saves current exception as __context__ and + __cause__. + */ +PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( + PyObject *exception, + const char *format, /* ASCII-encoded string */ + ... + ); + +PyAPI_FUNC(int) _PyException_AddNote( + PyObject *exc, + PyObject *note); + +PyAPI_FUNC(int) _PyErr_CheckSignals(void); + +/* Support for adding program text to SyntaxErrors */ + +PyAPI_FUNC(PyObject *) _PyErr_ProgramDecodedTextObject( + PyObject *filename, + int lineno, + const char* encoding); + +PyAPI_FUNC(PyObject *) _PyUnicodeTranslateError_Create( + PyObject *object, + Py_ssize_t start, + Py_ssize_t end, + const char *reason /* UTF-8 encoded string */ + ); + +PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalErrorFormat( + const char *func, + const char *format, + ...); + +extern PyObject *_PyErr_SetImportErrorWithNameFrom( + PyObject *, + PyObject *, + PyObject *, + PyObject *); + + /* runtime lifecycle */ extern PyStatus _PyErr_InitTypes(PyInterpreterState *); diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 9c6a9cddba2258..4d120d4e8af3a7 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -10,6 +10,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_object.h" +#include "pycore_pyerrors.h" // _Py_FatalErrorFormat() #include "structmember.h" // PyMemberDef #include "_iomodule.h" diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index caeedbddb8d88b..dba8ab61e41e70 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -21,11 +21,17 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "cursor.h" #include "microprotocols.h" #include "module.h" #include "util.h" +#include "pycore_pyerrors.h" // _PyErr_FormatFromCause() + typedef enum { TYPE_LONG, TYPE_FLOAT, diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index d4fccae65244c5..3e500b555e70ff 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -4,9 +4,10 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_interp.h" // PyInterpreterState.importlib -#include "pycore_object.h" // _PyType_AllocNoTrack -#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_modsupport.h" // _PyModule_CreateInitialized() +#include "pycore_moduleobject.h" // _PyModule_GetDef() +#include "pycore_object.h" // _PyType_AllocNoTrack +#include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "structmember.h" // PyMemberDef diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 9620a8fbb44cac..eb68d7c030d293 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -2,10 +2,10 @@ #include "Python.h" #include "pycore_code.h" // stats -#include "pycore_pystate.h" // _PyInterpreterState_GET - #include "pycore_obmalloc.h" +#include "pycore_pyerrors.h" // _Py_FatalErrorFormat() #include "pycore_pymem.h" +#include "pycore_pystate.h" // _PyInterpreterState_GET #include // malloc() #include diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 79402714f23b9d..12e379d0c7e6cd 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -50,6 +50,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_long.h" // _PyLong_FormatWriter() #include "pycore_object.h" // _PyObject_GC_TRACK(), _Py_FatalRefcountError() #include "pycore_pathconfig.h" // _Py_DumpPathConfig() +#include "pycore_pyerrors.h" // _PyUnicodeTranslateError_Create() #include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c index af529057f50e70..e543d40ccd8ab7 100644 --- a/Parser/pegen_errors.c +++ b/Parser/pegen_errors.c @@ -1,6 +1,7 @@ #include #include +#include "pycore_pyerrors.h" // _PyErr_ProgramDecodedTextObject() #include "tokenizer.h" #include "pegen.h" diff --git a/Python/importdl.c b/Python/importdl.c index eb6b808ecba1d5..9ab0a5ad33aaac 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_call.h" #include "pycore_import.h" +#include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" #include "pycore_runtime.h" From 60e41a0cbbe1a43e504b50a454efe653aba78a1a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 13:00:35 +0200 Subject: [PATCH 237/446] gh-104146: Remove unused attr 'parameter_indent' from clinic.DLParser (#106358) --- Tools/clinic/clinic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 125604bff97f7c..2e46131d4e336a 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4326,7 +4326,6 @@ def __init__(self, clinic: Clinic) -> None: def reset(self) -> None: self.function = None self.state = self.state_dsl_start - self.parameter_indent = None self.keyword_only = False self.positional_only = False self.group = 0 From 0da4c883cf4185efe27b711c3e0a1e6e94397610 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 15:14:59 +0200 Subject: [PATCH 238/446] gh-106359: Fix corner case bugs in Argument Clinic converter parser (#106361) DSLParser.parse_converter() could return unusable kwdicts in some rare cases Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 16 ++++++++++++++++ ...023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst | 2 ++ Tools/clinic/clinic.py | 16 +++++++++------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index a6ce9c2570cb62..fab2d2bb0bdbe4 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -813,6 +813,22 @@ def test_other_bizarre_things_in_annotations_fail(self): ) self.assertEqual(s, expected_failure_message) + def test_kwarg_splats_disallowed_in_function_call_annotations(self): + expected_error_msg = ( + "Error on line 0:\n" + "Cannot use a kwarg splat in a function-call annotation\n" + ) + dataset = ( + 'module fo\nfo.barbaz\n o: bool(**{None: "bang!"})', + 'module fo\nfo.barbaz -> bool(**{None: "bang!"})', + 'module fo\nfo.barbaz -> bool(**{"bang": 42})', + 'module fo\nfo.barbaz\n o: bool(**{"bang": None})', + ) + for fn in dataset: + with self.subTest(fn=fn): + out = self.parse_function_should_fail(fn) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst new file mode 100644 index 00000000000000..600c265391ec5b --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-07-03-14-06-19.gh-issue-106359.RfJuR0.rst @@ -0,0 +1,2 @@ +Argument Clinic now explicitly forbids "kwarg splats" in function calls used as +annotations. diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2e46131d4e336a..47038f98aabd75 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4291,6 +4291,7 @@ def dedent(self, line): StateKeeper = Callable[[str | None], None] +ConverterArgs = dict[str, Any] class DSLParser: function: Function | None @@ -5033,10 +5034,10 @@ def bad_node(self, node): key = f"{parameter_name}_as_{c_name}" if c_name else parameter_name self.function.parameters[key] = p - KwargDict = dict[str | None, Any] - @staticmethod - def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]: + def parse_converter( + annotation: ast.expr | None + ) -> tuple[str, bool, ConverterArgs]: match annotation: case ast.Constant(value=str() as value): return value, True, {} @@ -5044,10 +5045,11 @@ def parse_converter(annotation: ast.expr | None) -> tuple[str, bool, KwargDict]: return name, False, {} case ast.Call(func=ast.Name(name)): symbols = globals() - kwargs = { - node.arg: eval_ast_expr(node.value, symbols) - for node in annotation.keywords - } + kwargs: ConverterArgs = {} + for node in annotation.keywords: + if not isinstance(node.arg, str): + fail("Cannot use a kwarg splat in a function-call annotation") + kwargs[node.arg] = eval_ast_expr(node.value, symbols) return name, False, kwargs case _: fail( From 2e2daac2f11cbd762601382e759048fdbabba5bc Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 16:03:31 +0200 Subject: [PATCH 239/446] gh-104050: Add more type hints to Argument Clinic DSLParser() (#106354) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 47038f98aabd75..41d4274fc744e0 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4,6 +4,7 @@ # Copyright 2012-2013 by Larry Hastings. # Licensed to the PSF under a contributor agreement. # +from __future__ import annotations import abc import ast @@ -2448,7 +2449,7 @@ def __init__( cls: Class | None = None, c_basename: str | None = None, full_name: str | None = None, - return_converter: ReturnConverterType, + return_converter: CReturnConverter, return_annotation = inspect.Signature.empty, docstring: str | None = None, kind: str = CALLABLE, @@ -2467,7 +2468,7 @@ def __init__( self.docstring = docstring or '' self.kind = kind self.coexist = coexist - self.self_converter = None + self.self_converter: self_converter | None = None # docstring_only means "don't generate a machine-readable # signature, just a normal docstring". it's True for # functions with optional groups because we can't represent @@ -2531,7 +2532,7 @@ class Parameter: def __init__( self, name: str, - kind: str, + kind: inspect._ParameterKind, *, default = inspect.Parameter.empty, function: Function, @@ -4539,7 +4540,7 @@ def state_dsl_start(self, line: str | None) -> None: self.next(self.state_modulename_name, line) - def state_modulename_name(self, line): + def state_modulename_name(self, line: str | None) -> None: # looking for declaration, which establishes the leftmost column # line should be # modulename.fnname [as c_basename] [-> return annotation] @@ -4556,13 +4557,14 @@ def state_modulename_name(self, line): # this line is permitted to start with whitespace. # we'll call this number of spaces F (for "function"). - if not line.strip(): + if not self.valid_line(line): return self.indent.infer(line) # are we cloning? before, equals, existing = line.rpartition('=') + c_basename: str | None if equals: full_name, _, c_basename = before.partition(' as ') full_name = full_name.strip() @@ -4665,8 +4667,9 @@ def state_modulename_name(self, line): if cls and type == "PyObject *": kwargs['type'] = cls.typedef sc = self.function.self_converter = self_converter(name, name, self.function, **kwargs) - p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc) - self.function.parameters[sc.name] = p_self + p_self = Parameter(name, inspect.Parameter.POSITIONAL_ONLY, + function=self.function, converter=sc) + self.function.parameters[name] = p_self (cls or module).functions.append(self.function) self.next(self.state_parameters_start) @@ -4740,7 +4743,7 @@ def state_modulename_name(self, line): ps_start, ps_left_square_before, ps_group_before, ps_required, \ ps_optional, ps_group_after, ps_right_square_after = range(7) - def state_parameters_start(self, line: str) -> None: + def state_parameters_start(self, line: str | None) -> None: if not self.valid_line(line): return From 58906213cc5d8f2be311664766b4923ef29dae1f Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Mon, 3 Jul 2023 08:25:22 -0600 Subject: [PATCH 240/446] gh-91053: make func watcher tests resilient to other func watchers (#106286) --- Modules/_testcapi/watchers.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index d2c71fb401d36a..7167943fffab39 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -432,9 +432,9 @@ allocate_too_many_code_watchers(PyObject *self, PyObject *args) // Test function watchers -#define NUM_FUNC_WATCHERS 2 -static PyObject *pyfunc_watchers[NUM_FUNC_WATCHERS]; -static int func_watcher_ids[NUM_FUNC_WATCHERS] = {-1, -1}; +#define NUM_TEST_FUNC_WATCHERS 2 +static PyObject *pyfunc_watchers[NUM_TEST_FUNC_WATCHERS]; +static int func_watcher_ids[NUM_TEST_FUNC_WATCHERS] = {-1, -1}; static PyObject * get_id(PyObject *obj) @@ -508,7 +508,7 @@ second_func_watcher_callback(PyFunction_WatchEvent event, return call_pyfunc_watcher(pyfunc_watchers[1], event, func, new_value); } -static PyFunction_WatchCallback func_watcher_callbacks[NUM_FUNC_WATCHERS] = { +static PyFunction_WatchCallback func_watcher_callbacks[NUM_TEST_FUNC_WATCHERS] = { first_func_watcher_callback, second_func_watcher_callback }; @@ -533,26 +533,25 @@ add_func_watcher(PyObject *self, PyObject *func) return NULL; } int idx = -1; - for (int i = 0; i < NUM_FUNC_WATCHERS; i++) { + for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) { if (func_watcher_ids[i] == -1) { idx = i; break; } } if (idx == -1) { - PyErr_SetString(PyExc_RuntimeError, "no free watchers"); - return NULL; - } - PyObject *result = PyLong_FromLong(idx); - if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no free test watchers"); return NULL; } func_watcher_ids[idx] = PyFunction_AddWatcher(func_watcher_callbacks[idx]); if (func_watcher_ids[idx] < 0) { - Py_DECREF(result); return NULL; } pyfunc_watchers[idx] = Py_NewRef(func); + PyObject *result = PyLong_FromLong(func_watcher_ids[idx]); + if (result == NULL) { + return NULL; + } return result; } @@ -569,7 +568,7 @@ clear_func_watcher(PyObject *self, PyObject *watcher_id_obj) return NULL; } int idx = -1; - for (int i = 0; i < NUM_FUNC_WATCHERS; i++) { + for (int i = 0; i < NUM_TEST_FUNC_WATCHERS; i++) { if (func_watcher_ids[i] == wid) { idx = i; break; From 2028a4f6d996d2a46cbc33d0b65fdae284ee71fc Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 3 Jul 2023 13:05:11 -0700 Subject: [PATCH 241/446] gh-106290: Fix edge cases around uops (#106319) - Tweak uops debugging output - Fix the bug from gh-106290 - Rename `SET_IP` to `SAVE_IP` (per https://github.com/faster-cpython/ideas/issues/558) - Add a `SAVE_IP` uop at the start of the trace (ditto) - Allow `unbound_local_error`; this gives us uops for `LOAD_FAST_CHECK`, `LOAD_CLOSURE`, and `DELETE_FAST` - Longer traces - Support `STORE_FAST_LOAD_FAST`, `STORE_FAST_STORE_FAST` - Add deps on pycore_uops.h to Makefile(.pre.in) --- Include/internal/pycore_uops.h | 2 +- Makefile.pre.in | 1 + Python/ceval.c | 62 ++--- Python/executor_cases.c.h | 291 +++++++++++++----------- Python/opcode_metadata.h | 6 +- Python/optimizer.c | 132 ++++++----- Tools/cases_generator/generate_cases.py | 14 +- 7 files changed, 274 insertions(+), 234 deletions(-) diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h index 0e88d7e7f4a3bd..5ed275fb857679 100644 --- a/Include/internal/pycore_uops.h +++ b/Include/internal/pycore_uops.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#define _Py_UOP_MAX_TRACE_LENGTH 16 +#define _Py_UOP_MAX_TRACE_LENGTH 32 typedef struct { int opcode; diff --git a/Makefile.pre.in b/Makefile.pre.in index dcb3b5eb06a1e9..41623bd2f1da7f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1800,6 +1800,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_unionobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject_generated.h \ + $(srcdir)/Include/internal/pycore_uops.h \ $(srcdir)/Include/internal/pycore_warnings.h \ $(srcdir)/Include/internal/pycore_weakref.h \ $(DTRACE_HEADERS) \ diff --git a/Python/ceval.c b/Python/ceval.c index 80ae85c24f0540..6ce1a6a636ed71 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2773,24 +2773,26 @@ void Py_LeaveRecursiveCall(void) _PyInterpreterFrame * _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer) { -#ifdef LLTRACE +#ifdef Py_DEBUG char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); int lltrace = 0; if (uop_debug != NULL && *uop_debug >= '0') { lltrace = *uop_debug - '0'; // TODO: Parse an int and all that } - if (lltrace >= 2) { - PyCodeObject *code = _PyFrame_GetCode(frame); - _Py_CODEUNIT *instr = frame->prev_instr + 1; - fprintf(stderr, - "Entering _PyUopExecute for %s (%s:%d) at offset %ld\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); - } +#define DPRINTF(level, ...) \ + if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); } +#else +#define DPRINTF(level, ...) #endif + DPRINTF(3, + "Entering _PyUopExecute for %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname), + PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename), + _PyFrame_GetCode(frame)->co_firstlineno, + (long)(frame->prev_instr + 1 - + (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive)); + PyThreadState *tstate = _PyThreadState_GET(); _PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor; @@ -2803,7 +2805,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject } OBJECT_STAT_INC(optimization_traces_executed); - _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive - 1; + _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; int pc = 0; int opcode; uint64_t operand; @@ -2812,14 +2814,11 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject opcode = self->trace[pc].opcode; operand = self->trace[pc].operand; oparg = (int)operand; -#ifdef LLTRACE - if (lltrace >= 3) { - const char *opname = opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]; - int stack_level = (int)(stack_pointer - _PyFrame_Stackbase(frame)); - fprintf(stderr, " uop %s, operand %" PRIu64 ", stack_level %d\n", - opname, operand, stack_level); - } -#endif + DPRINTF(3, + " uop %s, operand %" PRIu64 ", stack_level %d\n", + opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode], + operand, + (int)(stack_pointer - _PyFrame_Stackbase(frame))); pc++; OBJECT_STAT_INC(optimization_uops_executed); switch (opcode) { @@ -2828,7 +2827,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject #define ENABLE_SPECIALIZATION 0 #include "executor_cases.c.h" - case SET_IP: + case SAVE_IP: { frame->prev_instr = ip_offset + oparg; break; @@ -2836,6 +2835,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject case EXIT_TRACE: { + frame->prev_instr--; // Back up to just before destination _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(self); return frame; @@ -2850,6 +2850,13 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject } } +unbound_local_error: + format_exc_check_arg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(_PyFrame_GetCode(frame)->co_localsplusnames, oparg) + ); + goto error; + pop_4_error: STACK_SHRINK(1); pop_3_error: @@ -2861,11 +2868,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject error: // On ERROR_IF we return NULL as the frame. // The caller recovers the frame from cframe.current_frame. -#ifdef LLTRACE - if (lltrace >= 2) { - fprintf(stderr, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); - } -#endif + DPRINTF(2, "Error: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(self); return NULL; @@ -2873,11 +2876,8 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject deoptimize: // On DEOPT_IF we just repeat the last instruction. // This presumes nothing was popped from the stack (nor pushed). -#ifdef LLTRACE - if (lltrace >= 2) { - fprintf(stderr, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); - } -#endif + DPRINTF(2, "DEOPT: [Opcode %d, operand %" PRIu64 "]\n", opcode, operand); + frame->prev_instr--; // Back up to just before destination _PyFrame_SetStackPointer(frame, stack_pointer); Py_DECREF(self); return frame; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 546b3d9f50ac76..d1e0443db613d2 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -7,13 +7,25 @@ break; } + case LOAD_FAST_CHECK: { + PyObject *value; + #line 182 "Python/bytecodes.c" + value = GETLOCAL(oparg); + if (value == NULL) goto unbound_local_error; + Py_INCREF(value); + #line 17 "Python/executor_cases.c.h" + STACK_GROW(1); + stack_pointer[-1] = value; + break; + } + case LOAD_FAST: { PyObject *value; #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 17 "Python/executor_cases.c.h" + #line 29 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -25,7 +37,7 @@ value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; - #line 29 "Python/executor_cases.c.h" + #line 41 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -36,7 +48,7 @@ #line 209 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); - #line 40 "Python/executor_cases.c.h" + #line 52 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -46,7 +58,7 @@ PyObject *value = stack_pointer[-1]; #line 214 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 50 "Python/executor_cases.c.h" + #line 62 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -54,7 +66,7 @@ case POP_TOP: { PyObject *value = stack_pointer[-1]; #line 237 "Python/bytecodes.c" - #line 58 "Python/executor_cases.c.h" + #line 70 "Python/executor_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); break; @@ -64,7 +76,7 @@ PyObject *res; #line 241 "Python/bytecodes.c" res = NULL; - #line 68 "Python/executor_cases.c.h" + #line 80 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -75,7 +87,7 @@ PyObject *receiver = stack_pointer[-2]; #line 260 "Python/bytecodes.c" Py_DECREF(receiver); - #line 79 "Python/executor_cases.c.h" + #line 91 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; break; @@ -86,11 +98,11 @@ PyObject *res; #line 275 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 90 "Python/executor_cases.c.h" + #line 102 "Python/executor_cases.c.h" Py_DECREF(value); #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 94 "Python/executor_cases.c.h" + #line 106 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -101,7 +113,7 @@ #line 281 "Python/bytecodes.c" assert(PyBool_Check(value)); res = Py_IsFalse(value) ? Py_True : Py_False; - #line 105 "Python/executor_cases.c.h" + #line 117 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -111,7 +123,7 @@ #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 115 "Python/executor_cases.c.h" + #line 127 "Python/executor_cases.c.h" break; } @@ -126,12 +138,12 @@ res = Py_False; } else { - #line 130 "Python/executor_cases.c.h" + #line 142 "Python/executor_cases.c.h" Py_DECREF(value); #line 326 "Python/bytecodes.c" res = Py_True; } - #line 135 "Python/executor_cases.c.h" + #line 147 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -143,7 +155,7 @@ DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; - #line 147 "Python/executor_cases.c.h" + #line 159 "Python/executor_cases.c.h" Py_DECREF(value); stack_pointer[-1] = res; break; @@ -157,7 +169,7 @@ DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_False; - #line 161 "Python/executor_cases.c.h" + #line 173 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -174,12 +186,12 @@ } else { assert(Py_SIZE(value)); - #line 178 "Python/executor_cases.c.h" + #line 190 "Python/executor_cases.c.h" Py_DECREF(value); #line 354 "Python/bytecodes.c" res = Py_True; } - #line 183 "Python/executor_cases.c.h" + #line 195 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -193,11 +205,11 @@ assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 197 "Python/executor_cases.c.h" + #line 209 "Python/executor_cases.c.h" Py_DECREF(value); #line 364 "Python/bytecodes.c" res = Py_True; - #line 201 "Python/executor_cases.c.h" + #line 213 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -207,11 +219,11 @@ PyObject *res; #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 211 "Python/executor_cases.c.h" + #line 223 "Python/executor_cases.c.h" Py_DECREF(value); #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 215 "Python/executor_cases.c.h" + #line 227 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -222,7 +234,7 @@ #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 226 "Python/executor_cases.c.h" + #line 238 "Python/executor_cases.c.h" break; } @@ -236,7 +248,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 240 "Python/executor_cases.c.h" + #line 252 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -252,7 +264,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 256 "Python/executor_cases.c.h" + #line 268 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -268,7 +280,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 272 "Python/executor_cases.c.h" + #line 284 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -280,7 +292,7 @@ #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 284 "Python/executor_cases.c.h" + #line 296 "Python/executor_cases.c.h" break; } @@ -294,7 +306,7 @@ ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 298 "Python/executor_cases.c.h" + #line 310 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -310,7 +322,7 @@ ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 314 "Python/executor_cases.c.h" + #line 326 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -326,7 +338,7 @@ ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 330 "Python/executor_cases.c.h" + #line 342 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -338,7 +350,7 @@ #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 342 "Python/executor_cases.c.h" + #line 354 "Python/executor_cases.c.h" break; } @@ -352,7 +364,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 356 "Python/executor_cases.c.h" + #line 368 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -376,7 +388,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 380 "Python/executor_cases.c.h" + #line 392 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -400,7 +412,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 404 "Python/executor_cases.c.h" + #line 416 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -423,7 +435,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 427 "Python/executor_cases.c.h" + #line 439 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -447,7 +459,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 451 "Python/executor_cases.c.h" + #line 463 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -465,14 +477,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 469 "Python/executor_cases.c.h" + #line 481 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 476 "Python/executor_cases.c.h" + #line 488 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -485,7 +497,7 @@ PyObject *list = stack_pointer[-(2 + (oparg-1))]; #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 489 "Python/executor_cases.c.h" + #line 501 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -495,11 +507,11 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 499 "Python/executor_cases.c.h" + #line 511 "Python/executor_cases.c.h" Py_DECREF(v); #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 503 "Python/executor_cases.c.h" + #line 515 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -525,7 +537,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 529 "Python/executor_cases.c.h" + #line 541 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -540,7 +552,7 @@ int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 544 "Python/executor_cases.c.h" + #line 556 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -551,12 +563,12 @@ #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 555 "Python/executor_cases.c.h" + #line 567 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 560 "Python/executor_cases.c.h" + #line 572 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -567,11 +579,11 @@ #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 571 "Python/executor_cases.c.h" + #line 583 "Python/executor_cases.c.h" Py_DECREF(value); #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 575 "Python/executor_cases.c.h" + #line 587 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -583,12 +595,12 @@ #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 587 "Python/executor_cases.c.h" + #line 599 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 592 "Python/executor_cases.c.h" + #line 604 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -610,14 +622,14 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 614 "Python/executor_cases.c.h" + #line 626 "Python/executor_cases.c.h" Py_DECREF(obj); #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 621 "Python/executor_cases.c.h" + #line 633 "Python/executor_cases.c.h" Py_DECREF(obj); #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; @@ -632,7 +644,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 636 "Python/executor_cases.c.h" + #line 648 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -683,7 +695,7 @@ Py_DECREF(next_iter); } } - #line 687 "Python/executor_cases.c.h" + #line 699 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -699,7 +711,7 @@ format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 703 "Python/executor_cases.c.h" + #line 715 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 904 "Python/bytecodes.c" @@ -718,7 +730,7 @@ } if (iter == NULL) goto pop_1_error; - #line 722 "Python/executor_cases.c.h" + #line 734 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -728,7 +740,7 @@ #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 732 "Python/executor_cases.c.h" + #line 744 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -737,7 +749,7 @@ PyObject *value; #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 741 "Python/executor_cases.c.h" + #line 753 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -767,7 +779,7 @@ if (true) goto error; } } - #line 771 "Python/executor_cases.c.h" + #line 783 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -782,7 +794,7 @@ if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 786 "Python/executor_cases.c.h" + #line 798 "Python/executor_cases.c.h" Py_DECREF(v); #line 1121 "Python/bytecodes.c" if (true) goto pop_1_error; @@ -791,11 +803,11 @@ err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 795 "Python/executor_cases.c.h" + #line 807 "Python/executor_cases.c.h" Py_DECREF(v); #line 1128 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 799 "Python/executor_cases.c.h" + #line 811 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -818,7 +830,7 @@ name); goto error; } - #line 822 "Python/executor_cases.c.h" + #line 834 "Python/executor_cases.c.h" break; } @@ -832,7 +844,7 @@ STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 836 "Python/executor_cases.c.h" + #line 848 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -850,7 +862,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 854 "Python/executor_cases.c.h" + #line 866 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -868,7 +880,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 872 "Python/executor_cases.c.h" + #line 884 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -881,11 +893,11 @@ int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 885 "Python/executor_cases.c.h" + #line 897 "Python/executor_cases.c.h" Py_DECREF(seq); #line 1211 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 889 "Python/executor_cases.c.h" + #line 901 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } @@ -895,11 +907,11 @@ #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 899 "Python/executor_cases.c.h" + #line 911 "Python/executor_cases.c.h" Py_DECREF(owner); #line 1245 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 903 "Python/executor_cases.c.h" + #line 915 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -909,11 +921,11 @@ #line 1249 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 913 "Python/executor_cases.c.h" + #line 925 "Python/executor_cases.c.h" Py_DECREF(v); #line 1252 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 917 "Python/executor_cases.c.h" + #line 929 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -931,7 +943,7 @@ } goto error; } - #line 935 "Python/executor_cases.c.h" + #line 947 "Python/executor_cases.c.h" break; } @@ -945,7 +957,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 949 "Python/executor_cases.c.h" + #line 961 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -1011,11 +1023,20 @@ } } } - #line 1015 "Python/executor_cases.c.h" + #line 1027 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } + case DELETE_FAST: { + #line 1435 "Python/bytecodes.c" + PyObject *v = GETLOCAL(oparg); + if (v == NULL) goto unbound_local_error; + SETLOCAL(oparg, NULL); + #line 1037 "Python/executor_cases.c.h" + break; + } + case DELETE_DEREF: { #line 1452 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); @@ -1028,7 +1049,7 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1032 "Python/executor_cases.c.h" + #line 1053 "Python/executor_cases.c.h" break; } @@ -1070,7 +1091,7 @@ } Py_INCREF(value); } - #line 1074 "Python/executor_cases.c.h" + #line 1095 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } @@ -1085,7 +1106,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1089 "Python/executor_cases.c.h" + #line 1110 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1098,7 +1119,7 @@ PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1102 "Python/executor_cases.c.h" + #line 1123 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1115,7 +1136,7 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1119 "Python/executor_cases.c.h" + #line 1140 "Python/executor_cases.c.h" break; } @@ -1124,13 +1145,13 @@ PyObject *str; #line 1532 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1128 "Python/executor_cases.c.h" + #line 1149 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } #line 1534 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1134 "Python/executor_cases.c.h" + #line 1155 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1143,7 +1164,7 @@ #line 1538 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1147 "Python/executor_cases.c.h" + #line 1168 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1156,7 +1177,7 @@ #line 1543 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1160 "Python/executor_cases.c.h" + #line 1181 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1177,13 +1198,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1181 "Python/executor_cases.c.h" + #line 1202 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1187 "Python/executor_cases.c.h" + #line 1208 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1194,11 +1215,11 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 1566 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1198 "Python/executor_cases.c.h" + #line 1219 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1568 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1202 "Python/executor_cases.c.h" + #line 1223 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1221,7 +1242,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1225 "Python/executor_cases.c.h" + #line 1246 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1239,13 +1260,13 @@ if (map == NULL) goto error; - #line 1243 "Python/executor_cases.c.h" + #line 1264 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } #line 1597 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1249 "Python/executor_cases.c.h" + #line 1270 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1293,7 +1314,7 @@ Py_DECREF(ann_dict); } } - #line 1297 "Python/executor_cases.c.h" + #line 1318 "Python/executor_cases.c.h" break; } @@ -1311,14 +1332,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1315 "Python/executor_cases.c.h" + #line 1336 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); #line 1653 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1322 "Python/executor_cases.c.h" + #line 1343 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1334,12 +1355,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1338 "Python/executor_cases.c.h" + #line 1359 "Python/executor_cases.c.h" Py_DECREF(update); #line 1665 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1343 "Python/executor_cases.c.h" + #line 1364 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1352,12 +1373,12 @@ if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1356 "Python/executor_cases.c.h" + #line 1377 "Python/executor_cases.c.h" Py_DECREF(update); #line 1676 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1361 "Python/executor_cases.c.h" + #line 1382 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1372,7 +1393,7 @@ /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1376 "Python/executor_cases.c.h" + #line 1397 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1390,13 +1411,13 @@ STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1394 "Python/executor_cases.c.h" + #line 1415 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); #line 1772 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1400 "Python/executor_cases.c.h" + #line 1421 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1433,7 +1454,7 @@ res = res2; res2 = NULL; } - #line 1437 "Python/executor_cases.c.h" + #line 1458 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1456,7 +1477,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1460 "Python/executor_cases.c.h" + #line 1481 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1482,7 +1503,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1486 "Python/executor_cases.c.h" + #line 1507 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1505,7 +1526,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1509 "Python/executor_cases.c.h" + #line 1530 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1517,12 +1538,12 @@ PyObject *b; #line 2163 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1521 "Python/executor_cases.c.h" + #line 1542 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2165 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1526 "Python/executor_cases.c.h" + #line 1547 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1534,13 +1555,13 @@ PyObject *b; #line 2169 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1538 "Python/executor_cases.c.h" + #line 1559 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2171 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1544 "Python/executor_cases.c.h" + #line 1565 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1553,7 +1574,7 @@ PyObject *match; #line 2176 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1557 "Python/executor_cases.c.h" + #line 1578 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2178 "Python/bytecodes.c" @@ -1564,7 +1585,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1568 "Python/executor_cases.c.h" + #line 1589 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2186 "Python/bytecodes.c" @@ -1576,7 +1597,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1580 "Python/executor_cases.c.h" + #line 1601 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1589,18 +1610,18 @@ #line 2197 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1593 "Python/executor_cases.c.h" + #line 1614 "Python/executor_cases.c.h" Py_DECREF(right); #line 2200 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1600 "Python/executor_cases.c.h" + #line 1621 "Python/executor_cases.c.h" Py_DECREF(right); #line 2205 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1604 "Python/executor_cases.c.h" + #line 1625 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1614,7 +1635,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1618 "Python/executor_cases.c.h" + #line 1639 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1630,7 +1651,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1634 "Python/executor_cases.c.h" + #line 1655 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -1642,7 +1663,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1646 "Python/executor_cases.c.h" + #line 1667 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1654,7 +1675,7 @@ #line 2327 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1658 "Python/executor_cases.c.h" + #line 1679 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1666,7 +1687,7 @@ #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1670 "Python/executor_cases.c.h" + #line 1691 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1680,7 +1701,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1684 "Python/executor_cases.c.h" + #line 1705 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1692,11 +1713,11 @@ #line 2343 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1696 "Python/executor_cases.c.h" + #line 1717 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2346 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1700 "Python/executor_cases.c.h" + #line 1721 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1727,11 +1748,11 @@ if (iter == NULL) { goto error; } - #line 1731 "Python/executor_cases.c.h" + #line 1752 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2373 "Python/bytecodes.c" } - #line 1735 "Python/executor_cases.c.h" + #line 1756 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1762,7 +1783,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 1766 "Python/executor_cases.c.h" + #line 1787 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1781,7 +1802,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 1785 "Python/executor_cases.c.h" + #line 1806 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -1798,7 +1819,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 1802 "Python/executor_cases.c.h" + #line 1823 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1818,7 +1839,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 1822 "Python/executor_cases.c.h" + #line 1843 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -1851,7 +1872,7 @@ default: Py_UNREACHABLE(); } - #line 1855 "Python/executor_cases.c.h" + #line 1876 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -1864,13 +1885,13 @@ PyObject *slice; #line 3491 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 1868 "Python/executor_cases.c.h" + #line 1889 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3493 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 1874 "Python/executor_cases.c.h" + #line 1895 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -1887,7 +1908,7 @@ result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 1891 "Python/executor_cases.c.h" + #line 1912 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -1906,7 +1927,7 @@ else { res = value; } - #line 1910 "Python/executor_cases.c.h" + #line 1931 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -1920,7 +1941,7 @@ Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 1924 "Python/executor_cases.c.h" + #line 1945 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1932,7 +1953,7 @@ #line 3526 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 1936 "Python/executor_cases.c.h" + #line 1957 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -1943,7 +1964,7 @@ PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3551 "Python/bytecodes.c" assert(oparg >= 2); - #line 1947 "Python/executor_cases.c.h" + #line 1968 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 6a42775e091208..ac3d800d8fe0fe 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -20,7 +20,7 @@ 0) #define EXIT_TRACE 300 -#define SET_IP 301 +#define SAVE_IP 301 #define _GUARD_BOTH_INT 302 #define _BINARY_OP_MULTIPLY_INT 303 #define _BINARY_OP_ADD_INT 304 @@ -1164,6 +1164,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { }; const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } }, + [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } }, [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { LOAD_FAST_AND_CLEAR, 0, 0 } } }, [LOAD_CONST] = { .nuops = 1, .uops = { { LOAD_CONST, 0, 0 } } }, @@ -1218,6 +1219,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, + [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, [LOAD_DEREF] = { .nuops = 1, .uops = { { LOAD_DEREF, 0, 0 } } }, @@ -1266,7 +1268,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { #ifdef Py_DEBUG const char * const _PyOpcode_uop_name[512] = { [300] = "EXIT_TRACE", - [301] = "SET_IP", + [301] = "SAVE_IP", [302] = "_GUARD_BOTH_INT", [303] = "_BINARY_OP_MULTIPLY_INT", [304] = "_BINARY_OP_ADD_INT", diff --git a/Python/optimizer.c b/Python/optimizer.c index b00825ade16e07..32f0b1477d203c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -282,11 +282,6 @@ PyUnstable_Optimizer_NewCounter(void) ///////////////////// Experimental UOp Optimizer ///////////////////// -#ifdef Py_DEBUG - /* For debugging the interpreter: */ -# define LLTRACE 1 /* Low-level trace feature */ -#endif - static void uop_dealloc(_PyUOpExecutorObject *self) { PyObject_Free(self); @@ -308,60 +303,81 @@ translate_bytecode_to_trace( _PyUOpInstruction *trace, int max_length) { -#ifdef LLTRACE + int trace_length = 0; + +#ifdef Py_DEBUG char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); int lltrace = 0; if (uop_debug != NULL && *uop_debug >= '0') { lltrace = *uop_debug - '0'; // TODO: Parse an int and all that } - if (lltrace >= 4) { - fprintf(stderr, - "Optimizing %s (%s:%d) at offset %ld\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); - } -#define ADD_TO_TRACE(OPCODE, OPERAND) \ - if (lltrace >= 2) { \ - const char *opname = (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)]; \ - fprintf(stderr, " ADD_TO_TRACE(%s, %" PRIu64 ")\n", opname, (uint64_t)(OPERAND)); \ - } \ - trace[trace_length].opcode = (OPCODE); \ - trace[trace_length].operand = (OPERAND); \ - trace_length++; +#define DPRINTF(level, ...) \ + if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); } #else -#define ADD_TO_TRACE(OPCODE, OPERAND) \ - trace[trace_length].opcode = (OPCODE); \ - trace[trace_length].operand = (OPERAND); \ - trace_length++; +#define DPRINTF(level, ...) #endif - int trace_length = 0; - // Always reserve space for one uop, plus SET_UP, plus EXIT_TRACE - while (trace_length + 3 <= max_length) { +#define ADD_TO_TRACE(OPCODE, OPERAND) \ + DPRINTF(2, \ + " ADD_TO_TRACE(%s, %" PRIu64 ")\n", \ + (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)], \ + (uint64_t)(OPERAND)); \ + assert(trace_length < max_length); \ + trace[trace_length].opcode = (OPCODE); \ + trace[trace_length].operand = (OPERAND); \ + trace_length++; + + DPRINTF(4, + "Optimizing %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + + for (;;) { + ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); int opcode = instr->op.code; uint64_t operand = instr->op.arg; switch (opcode) { case LOAD_FAST_LOAD_FAST: + case STORE_FAST_LOAD_FAST: + case STORE_FAST_STORE_FAST: { - // Reserve space for two uops (+ SETUP + EXIT_TRACE) + // Reserve space for two uops (+ SAVE_IP + EXIT_TRACE) if (trace_length + 4 > max_length) { + DPRINTF(1, "Ran out of space for LOAD_FAST_LOAD_FAST\n"); goto done; } uint64_t oparg1 = operand >> 4; uint64_t oparg2 = operand & 15; - ADD_TO_TRACE(LOAD_FAST, oparg1); - ADD_TO_TRACE(LOAD_FAST, oparg2); + switch (opcode) { + case LOAD_FAST_LOAD_FAST: + ADD_TO_TRACE(LOAD_FAST, oparg1); + ADD_TO_TRACE(LOAD_FAST, oparg2); + break; + case STORE_FAST_LOAD_FAST: + ADD_TO_TRACE(STORE_FAST, oparg1); + ADD_TO_TRACE(LOAD_FAST, oparg2); + break; + case STORE_FAST_STORE_FAST: + ADD_TO_TRACE(STORE_FAST, oparg1); + ADD_TO_TRACE(STORE_FAST, oparg2); + break; + default: + Py_FatalError("Missing case"); + } break; } default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; if (expansion->nuops > 0) { - // Reserve space for nuops (+ SETUP + EXIT_TRACE) + // Reserve space for nuops (+ SAVE_IP + EXIT_TRACE) int nuops = expansion->nuops; if (trace_length + nuops + 2 > max_length) { + DPRINTF(1, + "Ran out of space for %s\n", + opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]); goto done; } for (int i = 0; i < nuops; i++) { @@ -387,49 +403,45 @@ translate_bytecode_to_trace( Py_FatalError("garbled expansion"); } ADD_TO_TRACE(expansion->uops[i].uop, operand); - assert(expansion->uops[0].size == 0); // TODO } break; } - // fprintf(stderr, "Unsupported opcode %d\n", opcode); - goto done; // Break out of while loop + DPRINTF(2, + "Unsupported opcode %s\n", + opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]); + goto done; // Break out of loop } } instr++; // Add cache size for opcode instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; - ADD_TO_TRACE(SET_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); } + done: - if (trace_length > 0) { + // Skip short traces like SAVE_IP, LOAD_FAST, SAVE_IP, EXIT_TRACE + if (trace_length > 3) { ADD_TO_TRACE(EXIT_TRACE, 0); -#ifdef LLTRACE - if (lltrace >= 1) { - fprintf(stderr, - "Created a trace for %s (%s:%d) at offset %ld -- length %d\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive), - trace_length); - } -#endif + DPRINTF(1, + "Created a trace for %s (%s:%d) at offset %ld -- length %d\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive), + trace_length); + return trace_length; } else { -#ifdef LLTRACE - if (lltrace >= 4) { - fprintf(stderr, - "No trace for %s (%s:%d) at offset %ld\n", - PyUnicode_AsUTF8(code->co_qualname), - PyUnicode_AsUTF8(code->co_filename), - code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); - } -#endif + DPRINTF(4, + "No trace for %s (%s:%d) at offset %ld\n", + PyUnicode_AsUTF8(code->co_qualname), + PyUnicode_AsUTF8(code->co_filename), + code->co_firstlineno, + (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); } - return trace_length; + return 0; #undef ADD_TO_TRACE +#undef DPRINTF } static int diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 38be98034e0d83..657dfa93fd537d 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -308,8 +308,7 @@ class ActiveCacheEffect: FORBIDDEN_NAMES_IN_UOPS = ( - "resume_with_error", # Proxy for "goto", which isn't an IDENTIFIER - "unbound_local_error", + "resume_with_error", "kwnames", "next_instr", "oparg1", # Proxy for super-instructions like LOAD_FAST_LOAD_FAST @@ -401,20 +400,25 @@ def __init__(self, inst: parser.InstDef): def is_viable_uop(self) -> bool: """Whether this instruction is viable as a uop.""" if self.always_exits: + # print(f"Skipping {self.name} because it always exits") return False if self.instr_flags.HAS_ARG_FLAG: # If the instruction uses oparg, it cannot use any caches if self.active_caches: + # print(f"Skipping {self.name} because it uses oparg and caches") return False else: # If it doesn't use oparg, it can have one cache entry if len(self.active_caches) > 1: + # print(f"Skipping {self.name} because it has >1 cache entries") return False + res = True for forbidden in FORBIDDEN_NAMES_IN_UOPS: # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions if variable_used(self.inst, forbidden): - return False - return True + # print(f"Skipping {self.name} because it uses {forbidden}") + res = False + return res def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None: """Write one instruction, sans prologue and epilogue.""" @@ -1323,7 +1327,7 @@ def add(name: str) -> None: self.out.emit(make_text(name, counter)) counter += 1 add("EXIT_TRACE") - add("SET_IP") + add("SAVE_IP") for instr in self.instrs.values(): if instr.kind == "op" and instr.is_viable_uop(): add(instr.name) From bf06c6825cadeda54a9c0848fa51463a0e0b2cf8 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Tue, 4 Jul 2023 04:10:01 +0800 Subject: [PATCH 242/446] gh-106078: Move `context template` to decimal module global state (#106346) --- Modules/_decimal/_decimal.c | 59 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 3 -- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index da623725003428..6da5095b91018a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -49,6 +49,14 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; + + /* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ + PyObject *default_context_template; + + /* Basic and extended context templates */ + PyObject *basic_context_template; + PyObject *extended_context_template; } decimal_state; static decimal_state global_state; @@ -147,14 +155,6 @@ static PyDecContextObject *cached_context = NULL; static PyObject *current_context_var = NULL; #endif -/* Template for creating new thread contexts, calling Context() without - * arguments and initializing the module_context on first access. */ -static PyObject *default_context_template = NULL; -/* Basic and extended context templates */ -static PyObject *basic_context_template = NULL; -static PyObject *extended_context_template = NULL; - - /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) @@ -1272,8 +1272,8 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) ctx = CTX(self); - if (default_context_template) { - *ctx = *CTX(default_context_template); + if (state->default_context_template) { + *ctx = *CTX(state->default_context_template); } else { *ctx = dflt_ctx; @@ -1576,7 +1576,7 @@ current_context_from_dict(void) } /* Set up a new thread local context. */ - tl_context = context_copy(default_context_template, NULL); + tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } @@ -1649,9 +1649,9 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || - v == basic_context_template || - v == extended_context_template) { + if (v == state->default_context_template || + v == state->basic_context_template || + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -1675,7 +1675,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) static PyObject * init_current_context(void) { - PyObject *tl_context = context_copy(default_context_template, NULL); + decimal_state *state = GLOBAL_STATE(); + PyObject *tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } @@ -1730,9 +1731,9 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || - v == basic_context_template || - v == extended_context_template) { + if (v == state->default_context_template || + v == state->basic_context_template || + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -5980,10 +5981,10 @@ PyInit__decimal(void) /* Init default context template first */ - ASSIGN_PTR(default_context_template, + ASSIGN_PTR(state->default_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); CHECK_INT(PyModule_AddObject(m, "DefaultContext", - Py_NewRef(default_context_template))); + Py_NewRef(state->default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); @@ -5995,18 +5996,18 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); /* Init basic context template */ - ASSIGN_PTR(basic_context_template, + ASSIGN_PTR(state->basic_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); - init_basic_context(basic_context_template); + init_basic_context(state->basic_context_template); CHECK_INT(PyModule_AddObject(m, "BasicContext", - Py_NewRef(basic_context_template))); + Py_NewRef(state->basic_context_template))); /* Init extended context template */ - ASSIGN_PTR(extended_context_template, + ASSIGN_PTR(state->extended_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); - init_extended_context(extended_context_template); + init_extended_context(state->extended_context_template); CHECK_INT(PyModule_AddObject(m, "ExtendedContext", - Py_NewRef(extended_context_template))); + Py_NewRef(state->extended_context_template))); /* Init mpd_ssize_t constants */ @@ -6046,14 +6047,14 @@ PyInit__decimal(void) Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ #else Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ #endif - Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */ return NULL; /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 8fdc54df2b0722..ad3d9b6513d69c 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -422,10 +422,7 @@ Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - global_state - -Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - -Modules/_decimal/_decimal.c - default_context_template - -Modules/_decimal/_decimal.c - extended_context_template - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - From 7f4c8121db62a9f72f00f2d9f73381e82f289581 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 22:16:50 +0200 Subject: [PATCH 243/446] gh-106368: Increase Argument Clinic test coverage (#106369) Add tests for 'self' and 'defining_class' converter requirements. --- Lib/test/test_clinic.py | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index fab2d2bb0bdbe4..51d2ac972752fd 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -829,6 +829,63 @@ def test_kwarg_splats_disallowed_in_function_call_annotations(self): out = self.parse_function_should_fail(fn) self.assertEqual(out, expected_error_msg) + def test_self_param_placement(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'self' parameter, if specified, must be the very first thing " + "in the parameter block.\n" + ) + block = """ + module foo + foo.func + a: int + self: self(type="PyObject *") + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_self_param_cannot_be_optional(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'self' parameter cannot be marked optional.\n" + ) + block = """ + module foo + foo.func + self: self(type="PyObject *") = None + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_defining_class_param_placement(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'defining_class' parameter, if specified, must either be the " + "first thing in the parameter block, or come just after 'self'.\n" + ) + block = """ + module foo + foo.func + self: self(type="PyObject *") + a: int + cls: defining_class + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + + def test_defining_class_param_cannot_be_optional(self): + expected_error_msg = ( + "Error on line 0:\n" + "A 'defining_class' parameter cannot be marked optional.\n" + ) + block = """ + module foo + foo.func + cls: defining_class(type="PyObject *") = None + """ + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo From e5862113dde7a66b08f1ece542a3cfaf0a3d9080 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 3 Jul 2023 21:28:27 +0100 Subject: [PATCH 244/446] GH-104584: Fix ENTER_EXECUTOR (GH-106141) * Check eval-breaker in ENTER_EXECUTOR. * Make sure that frame->prev_instr is set before entering executor. --- Include/internal/pycore_ceval.h | 2 + Python/bytecodes.c | 19 +- Python/ceval.c | 70 +------ Python/ceval_gil.c | 61 +++++- Python/ceval_macros.h | 4 +- Python/executor_cases.c.h | 44 ++--- Python/generated_cases.c.h | 339 ++++++++++++++++---------------- Python/opcode_metadata.h | 2 +- 8 files changed, 272 insertions(+), 269 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 9e9b523e7c2222..46bc18cff86d5a 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -152,6 +152,8 @@ extern struct _PyInterpreterFrame* _PyEval_GetFrame(void); extern PyObject* _Py_MakeCoro(PyFunctionObject *func); +/* Handle signals, pending calls, GIL drop request + and asynchronous exception */ extern int _Py_HandlePending(PyThreadState *tstate); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8aab7ebc5cf0cb..f69ac2beef4c20 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -141,8 +141,8 @@ dummy_func( ERROR_IF(err, error); next_instr--; } - else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { - goto handle_eval_breaker; + else if (oparg < 2) { + CHECK_EVAL_BREAKER(); } } @@ -158,6 +158,9 @@ dummy_func( next_instr--; } else { + if (oparg < 2) { + CHECK_EVAL_BREAKER(); + } _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, next_instr-1); @@ -168,9 +171,6 @@ dummy_func( next_instr = frame->prev_instr; DISPATCH(); } - if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { - goto handle_eval_breaker; - } } } @@ -2223,6 +2223,7 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { + CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -2240,7 +2241,6 @@ dummy_func( goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - CHECK_EVAL_BREAKER(); } pseudo(JUMP) = { @@ -2254,8 +2254,13 @@ dummy_func( }; inst(ENTER_EXECUTOR, (--)) { + CHECK_EVAL_BREAKER(); + PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; + int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00); + JUMPBY(1-original_oparg); + frame->prev_instr = next_instr - 1; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { @@ -3570,8 +3575,8 @@ dummy_func( } inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) { - INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); CHECK_EVAL_BREAKER(); + INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); } inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) { diff --git a/Python/ceval.c b/Python/ceval.c index 6ce1a6a636ed71..9bcb83f9c993cf 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -763,68 +763,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); -handle_eval_breaker: - - /* Do periodic things, like check for signals and async I/0. - * We need to do reasonably frequently, but not too frequently. - * All loops should include a check of the eval breaker. - * We also check on return from any builtin function. - * - * ## More Details ### - * - * The eval loop (this function) normally executes the instructions - * of a code object sequentially. However, the runtime supports a - * number of out-of-band execution scenarios that may pause that - * sequential execution long enough to do that out-of-band work - * in the current thread using the current PyThreadState. - * - * The scenarios include: - * - * - cyclic garbage collection - * - GIL drop requests - * - "async" exceptions - * - "pending calls" (some only in the main thread) - * - signal handling (only in the main thread) - * - * When the need for one of the above is detected, the eval loop - * pauses long enough to handle the detected case. Then, if doing - * so didn't trigger an exception, the eval loop resumes executing - * the sequential instructions. - * - * To make this work, the eval loop periodically checks if any - * of the above needs to happen. The individual checks can be - * expensive if computed each time, so a while back we switched - * to using pre-computed, per-interpreter variables for the checks, - * and later consolidated that to a single "eval breaker" variable - * (now a PyInterpreterState field). - * - * For the longest time, the eval breaker check would happen - * frequently, every 5 or so times through the loop, regardless - * of what instruction ran last or what would run next. Then, in - * early 2021 (gh-18334, commit 4958f5d), we switched to checking - * the eval breaker less frequently, by hard-coding the check to - * specific places in the eval loop (e.g. certain instructions). - * The intent then was to check after returning from calls - * and on the back edges of loops. - * - * In addition to being more efficient, that approach keeps - * the eval loop from running arbitrary code between instructions - * that don't handle that well. (See gh-74174.) - * - * Currently, the eval breaker check happens here at the - * "handle_eval_breaker" label. Some instructions come here - * explicitly (goto) and some indirectly. Notably, the check - * happens on back edges in the control flow graph, which - * pretty much applies to all loops and most calls. - * (See bytecodes.c for exact information.) - * - * One consequence of this approach is that it might not be obvious - * how to force any specific thread to pick up the eval breaker, - * or for any specific thread to not pick it up. Mostly this - * involves judicious uses of locks and careful ordering of code, - * while avoiding code that might trigger the eval breaker - * until so desired. - */ if (_Py_HandlePending(tstate) != 0) { goto error; } @@ -2796,13 +2734,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject PyThreadState *tstate = _PyThreadState_GET(); _PyUOpExecutorObject *self = (_PyUOpExecutorObject *)executor; - // Equivalent to CHECK_EVAL_BREAKER() - _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); - if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { - if (_Py_HandlePending(tstate) != 0) { - goto error; - } - } + CHECK_EVAL_BREAKER(); OBJECT_STAT_INC(optimization_traces_executed); _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index c6b1f9ef689ee1..7c9ad07cc7207b 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -1052,8 +1052,65 @@ _PyEval_FiniState(struct _ceval_state *ceval) } } -/* Handle signals, pending calls, GIL drop request - and asynchronous exception */ + +/* Do periodic things, like check for signals and async I/0. +* We need to do reasonably frequently, but not too frequently. +* All loops should include a check of the eval breaker. +* We also check on return from any builtin function. +* +* ## More Details ### +* +* The eval loop (this function) normally executes the instructions +* of a code object sequentially. However, the runtime supports a +* number of out-of-band execution scenarios that may pause that +* sequential execution long enough to do that out-of-band work +* in the current thread using the current PyThreadState. +* +* The scenarios include: +* +* - cyclic garbage collection +* - GIL drop requests +* - "async" exceptions +* - "pending calls" (some only in the main thread) +* - signal handling (only in the main thread) +* +* When the need for one of the above is detected, the eval loop +* pauses long enough to handle the detected case. Then, if doing +* so didn't trigger an exception, the eval loop resumes executing +* the sequential instructions. +* +* To make this work, the eval loop periodically checks if any +* of the above needs to happen. The individual checks can be +* expensive if computed each time, so a while back we switched +* to using pre-computed, per-interpreter variables for the checks, +* and later consolidated that to a single "eval breaker" variable +* (now a PyInterpreterState field). +* +* For the longest time, the eval breaker check would happen +* frequently, every 5 or so times through the loop, regardless +* of what instruction ran last or what would run next. Then, in +* early 2021 (gh-18334, commit 4958f5d), we switched to checking +* the eval breaker less frequently, by hard-coding the check to +* specific places in the eval loop (e.g. certain instructions). +* The intent then was to check after returning from calls +* and on the back edges of loops. +* +* In addition to being more efficient, that approach keeps +* the eval loop from running arbitrary code between instructions +* that don't handle that well. (See gh-74174.) +* +* Currently, the eval breaker check happens on back edges in +* the control flow graph, which pretty much applies to all loops, +* and most calls. +* (See bytecodes.c for exact information.) +* +* One consequence of this approach is that it might not be obvious +* how to force any specific thread to pick up the eval breaker, +* or for any specific thread to not pick it up. Mostly this +* involves judicious uses of locks and careful ordering of code, +* while avoiding code that might trigger the eval breaker +* until so desired. +*/ int _Py_HandlePending(PyThreadState *tstate) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 0d41ef5a14cef4..72800aaaaa2ac4 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -117,7 +117,9 @@ #define CHECK_EVAL_BREAKER() \ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \ if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker)) { \ - goto handle_eval_breaker; \ + if (_Py_HandlePending(tstate) != 0) { \ + goto error; \ + } \ } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index d1e0443db613d2..39a4490e51c24a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1629,7 +1629,7 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2304 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -1646,7 +1646,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2312 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -1655,7 +1655,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2317 "Python/bytecodes.c" + #line 2322 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1672,7 +1672,7 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2327 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 1679 "Python/executor_cases.c.h" @@ -1684,7 +1684,7 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 1691 "Python/executor_cases.c.h" @@ -1697,7 +1697,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2337 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -1710,12 +1710,12 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2343 "Python/bytecodes.c" + #line 2348 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 1717 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2346 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 1721 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1725,7 +1725,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2350 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1750,7 +1750,7 @@ } #line 1752 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2373 "Python/bytecodes.c" + #line 2378 "Python/bytecodes.c" } #line 1756 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1762,7 +1762,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2605 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -1792,7 +1792,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2644 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -1811,7 +1811,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3013 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1827,7 +1827,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3427 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1847,7 +1847,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3441 "Python/bytecodes.c" + #line 3446 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1883,13 +1883,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3491 "Python/bytecodes.c" + #line 3496 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 1889 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3493 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 1895 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -1901,7 +1901,7 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3497 "Python/bytecodes.c" + #line 3502 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -1916,7 +1916,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3506 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1936,7 +1936,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3519 "Python/bytecodes.c" + #line 3524 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -1950,7 +1950,7 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3526 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 1957 "Python/executor_cases.c.h" @@ -1962,7 +1962,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3551 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" assert(oparg >= 2); #line 1968 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 21cd2d0126ab30..eb2422943984b1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -17,8 +17,8 @@ if (err) goto error; next_instr--; } - else if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { - goto handle_eval_breaker; + else if (oparg < 2) { + CHECK_EVAL_BREAKER(); } #line 24 "Python/generated_cases.c.h" DISPATCH(); @@ -37,6 +37,9 @@ next_instr--; } else { + if (oparg < 2) { + CHECK_EVAL_BREAKER(); + } _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( tstate, oparg > 0, frame, next_instr-1); @@ -47,9 +50,6 @@ next_instr = frame->prev_instr; DISPATCH(); } - if (_Py_atomic_load_relaxed_int32(&tstate->interp->ceval.eval_breaker) && oparg < 2) { - goto handle_eval_breaker; - } } #line 55 "Python/generated_cases.c.h" DISPATCH(); @@ -3182,6 +3182,7 @@ TARGET(JUMP_BACKWARD) { #line 2226 "Python/bytecodes.c" + CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3199,15 +3200,19 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3203 "Python/generated_cases.c.h" - CHECK_EVAL_BREAKER(); + #line 3204 "Python/generated_cases.c.h" DISPATCH(); } TARGET(ENTER_EXECUTOR) { #line 2257 "Python/bytecodes.c" + CHECK_EVAL_BREAKER(); + PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; + int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00); + JUMPBY(1-original_oparg); + frame->prev_instr = next_instr - 1; Py_INCREF(executor); frame = executor->execute(executor, frame, stack_pointer); if (frame == NULL) { @@ -3215,81 +3220,81 @@ goto resume_with_error; } goto resume_frame; - #line 3219 "Python/generated_cases.c.h" + #line 3224 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2269 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3227 "Python/generated_cases.c.h" + #line 3232 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2274 "Python/bytecodes.c" + #line 2279 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3237 "Python/generated_cases.c.h" + #line 3242 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2279 "Python/bytecodes.c" + #line 2284 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3246 "Python/generated_cases.c.h" + #line 3251 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2281 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3251 "Python/generated_cases.c.h" + #line 3256 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2286 "Python/bytecodes.c" + #line 2291 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3263 "Python/generated_cases.c.h" + #line 3268 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2291 "Python/bytecodes.c" + #line 2296 "Python/bytecodes.c" } - #line 3267 "Python/generated_cases.c.h" + #line 3272 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2295 "Python/bytecodes.c" + #line 2300 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3280 "Python/generated_cases.c.h" + #line 3285 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2304 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3293 "Python/generated_cases.c.h" + #line 3298 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3300,16 +3305,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2312 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3309 "Python/generated_cases.c.h" + #line 3314 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2317 "Python/bytecodes.c" + #line 2322 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3317,7 +3322,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3321 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3326,10 +3331,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2327 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3333 "Python/generated_cases.c.h" + #line 3338 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3338,10 +3343,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3345 "Python/generated_cases.c.h" + #line 3350 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3351,11 +3356,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2337 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3359 "Python/generated_cases.c.h" + #line 3364 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3364,14 +3369,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2343 "Python/bytecodes.c" + #line 2348 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3371 "Python/generated_cases.c.h" + #line 3376 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2346 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3375 "Python/generated_cases.c.h" + #line 3380 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3379,7 +3384,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2350 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3402,11 +3407,11 @@ if (iter == NULL) { goto error; } - #line 3406 "Python/generated_cases.c.h" + #line 3411 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2373 "Python/bytecodes.c" + #line 2378 "Python/bytecodes.c" } - #line 3410 "Python/generated_cases.c.h" + #line 3415 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3416,7 +3421,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2391 "Python/bytecodes.c" + #line 2396 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3448,7 +3453,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3452 "Python/generated_cases.c.h" + #line 3457 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3456,7 +3461,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2425 "Python/bytecodes.c" + #line 2430 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3482,14 +3487,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3486 "Python/generated_cases.c.h" + #line 3491 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2453 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3510,7 +3515,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3514 "Python/generated_cases.c.h" + #line 3519 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3520,7 +3525,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2476 "Python/bytecodes.c" + #line 2481 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3541,7 +3546,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3545 "Python/generated_cases.c.h" + #line 3550 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3551,7 +3556,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2499 "Python/bytecodes.c" + #line 2504 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3570,7 +3575,7 @@ if (next == NULL) { goto error; } - #line 3574 "Python/generated_cases.c.h" + #line 3579 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3579,7 +3584,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2520 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3595,14 +3600,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3599 "Python/generated_cases.c.h" + #line 3604 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2538 "Python/bytecodes.c" + #line 2543 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3625,16 +3630,16 @@ Py_DECREF(enter); goto error; } - #line 3629 "Python/generated_cases.c.h" + #line 3634 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2561 "Python/bytecodes.c" + #line 2566 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3638 "Python/generated_cases.c.h" + #line 3643 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3645,7 +3650,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2570 "Python/bytecodes.c" + #line 2575 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3671,16 +3676,16 @@ Py_DECREF(enter); goto error; } - #line 3675 "Python/generated_cases.c.h" + #line 3680 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2596 "Python/bytecodes.c" + #line 2601 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3684 "Python/generated_cases.c.h" + #line 3689 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3692,7 +3697,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2605 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3713,7 +3718,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3717 "Python/generated_cases.c.h" + #line 3722 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3722,7 +3727,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2644 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3732,7 +3737,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3736 "Python/generated_cases.c.h" + #line 3741 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3746,7 +3751,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2656 "Python/bytecodes.c" + #line 2661 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3763,7 +3768,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3767 "Python/generated_cases.c.h" + #line 3772 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3777,7 +3782,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2675 "Python/bytecodes.c" + #line 2680 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3787,7 +3792,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3791 "Python/generated_cases.c.h" + #line 3796 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3801,7 +3806,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2687 "Python/bytecodes.c" + #line 2692 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3815,7 +3820,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3819 "Python/generated_cases.c.h" + #line 3824 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3824,16 +3829,16 @@ } TARGET(KW_NAMES) { - #line 2703 "Python/bytecodes.c" + #line 2708 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3832 "Python/generated_cases.c.h" + #line 3837 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2709 "Python/bytecodes.c" + #line 2714 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3846,7 +3851,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3850 "Python/generated_cases.c.h" + #line 3855 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3856,7 +3861,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2755 "Python/bytecodes.c" + #line 2760 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3938,7 +3943,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3942 "Python/generated_cases.c.h" + #line 3947 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3950,7 +3955,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2843 "Python/bytecodes.c" + #line 2848 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3960,7 +3965,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3964 "Python/generated_cases.c.h" + #line 3969 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3969,7 +3974,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2855 "Python/bytecodes.c" + #line 2860 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3995,7 +4000,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3999 "Python/generated_cases.c.h" + #line 4004 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4003,7 +4008,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2883 "Python/bytecodes.c" + #line 2888 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4039,7 +4044,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4043 "Python/generated_cases.c.h" + #line 4048 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4047,7 +4052,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2921 "Python/bytecodes.c" + #line 2926 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4057,7 +4062,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4061 "Python/generated_cases.c.h" + #line 4066 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4070,7 +4075,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2933 "Python/bytecodes.c" + #line 2938 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4081,7 +4086,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4085 "Python/generated_cases.c.h" + #line 4090 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4095,7 +4100,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2947 "Python/bytecodes.c" + #line 2952 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4106,7 +4111,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4110 "Python/generated_cases.c.h" + #line 4115 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4119,7 +4124,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2961 "Python/bytecodes.c" + #line 2966 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4169,12 +4174,12 @@ frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); goto start_frame; - #line 4173 "Python/generated_cases.c.h" + #line 4178 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3013 "Python/bytecodes.c" + #line 3018 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4182,7 +4187,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4186 "Python/generated_cases.c.h" + #line 4191 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4192,7 +4197,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3023 "Python/bytecodes.c" + #line 3028 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4214,7 +4219,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4218 "Python/generated_cases.c.h" + #line 4223 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4228,7 +4233,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3048 "Python/bytecodes.c" + #line 3053 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4256,7 +4261,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4260 "Python/generated_cases.c.h" + #line 4265 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4270,7 +4275,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3079 "Python/bytecodes.c" + #line 3084 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4302,7 +4307,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4306 "Python/generated_cases.c.h" + #line 4311 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4316,7 +4321,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3114 "Python/bytecodes.c" + #line 3119 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4348,7 +4353,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4352 "Python/generated_cases.c.h" + #line 4357 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4362,7 +4367,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3149 "Python/bytecodes.c" + #line 3154 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4387,7 +4392,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4391 "Python/generated_cases.c.h" + #line 4396 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4400,7 +4405,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3176 "Python/bytecodes.c" + #line 3181 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4427,7 +4432,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4431 "Python/generated_cases.c.h" + #line 4436 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4439,7 +4444,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3206 "Python/bytecodes.c" + #line 3211 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4457,14 +4462,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4461 "Python/generated_cases.c.h" + #line 4466 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3226 "Python/bytecodes.c" + #line 3231 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4495,7 +4500,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4499 "Python/generated_cases.c.h" + #line 4504 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4508,7 +4513,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3260 "Python/bytecodes.c" + #line 3265 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4537,7 +4542,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4541 "Python/generated_cases.c.h" + #line 4546 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4550,7 +4555,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3292 "Python/bytecodes.c" + #line 3297 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4579,7 +4584,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4583 "Python/generated_cases.c.h" + #line 4588 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4592,7 +4597,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3324 "Python/bytecodes.c" + #line 3329 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4620,7 +4625,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4624 "Python/generated_cases.c.h" + #line 4629 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4630,9 +4635,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3355 "Python/bytecodes.c" + #line 3360 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4636 "Python/generated_cases.c.h" + #line 4641 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4641,7 +4646,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3359 "Python/bytecodes.c" + #line 3364 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4703,14 +4708,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4707 "Python/generated_cases.c.h" + #line 4712 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3421 "Python/bytecodes.c" + #line 3426 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4714 "Python/generated_cases.c.h" + #line 4719 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4721,7 +4726,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3427 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4733,7 +4738,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4737 "Python/generated_cases.c.h" + #line 4742 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4741,7 +4746,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3441 "Python/bytecodes.c" + #line 3446 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4766,14 +4771,14 @@ default: Py_UNREACHABLE(); } - #line 4770 "Python/generated_cases.c.h" + #line 4775 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3468 "Python/bytecodes.c" + #line 3473 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4794,7 +4799,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4798 "Python/generated_cases.c.h" + #line 4803 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4802,15 +4807,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3491 "Python/bytecodes.c" + #line 3496 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4808 "Python/generated_cases.c.h" + #line 4813 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3493 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4814 "Python/generated_cases.c.h" + #line 4819 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4820,14 +4825,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3497 "Python/bytecodes.c" + #line 3502 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4831 "Python/generated_cases.c.h" + #line 4836 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4835,7 +4840,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3506 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4846,7 +4851,7 @@ else { res = value; } - #line 4850 "Python/generated_cases.c.h" + #line 4855 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4855,12 +4860,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3519 "Python/bytecodes.c" + #line 3524 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4864 "Python/generated_cases.c.h" + #line 4869 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4869,10 +4874,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3526 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4876 "Python/generated_cases.c.h" + #line 4881 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4884,7 +4889,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3531 "Python/bytecodes.c" + #line 3536 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4899,12 +4904,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4903 "Python/generated_cases.c.h" + #line 4908 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3546 "Python/bytecodes.c" + #line 3551 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4908 "Python/generated_cases.c.h" + #line 4913 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4914,16 +4919,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3551 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" assert(oparg >= 2); - #line 4920 "Python/generated_cases.c.h" + #line 4925 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3555 "Python/bytecodes.c" + #line 3560 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4935,48 +4940,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4939 "Python/generated_cases.c.h" + #line 4944 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3569 "Python/bytecodes.c" + #line 3574 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4945 "Python/generated_cases.c.h" + #line 4950 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3573 "Python/bytecodes.c" - INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4952 "Python/generated_cases.c.h" + #line 3578 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); + INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); + #line 4958 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3578 "Python/bytecodes.c" + #line 3583 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4964 "Python/generated_cases.c.h" + #line 4969 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3586 "Python/bytecodes.c" + #line 3591 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4975 "Python/generated_cases.c.h" + #line 4980 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3594 "Python/bytecodes.c" + #line 3599 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4988,12 +4993,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4992 "Python/generated_cases.c.h" + #line 4997 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3608 "Python/bytecodes.c" + #line 3613 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5005,30 +5010,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5009 "Python/generated_cases.c.h" + #line 5014 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3622 "Python/bytecodes.c" + #line 3627 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5020 "Python/generated_cases.c.h" + #line 5025 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3630 "Python/bytecodes.c" + #line 3635 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5027 "Python/generated_cases.c.h" + #line 5032 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3635 "Python/bytecodes.c" + #line 3640 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5034 "Python/generated_cases.c.h" + #line 5039 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ac3d800d8fe0fe..82c98235892287 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -1087,7 +1087,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [JUMP_BACKWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [JUMP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [JUMP_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, From b4efdf8cda8fbbd0ca53b457d5f6e46a59348caf Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Mon, 3 Jul 2023 21:29:44 +0100 Subject: [PATCH 245/446] GH-106330: Fix matching of empty path in `pathlib.PurePath.match()` (GH-106331) We match paths using the `_lines` attribute, which is derived from the path's string representation. The bug arises because an empty path's string representation is `'.'` (not `''`), which is matched by the `'*'` wildcard. --- Lib/pathlib.py | 8 ++++++-- Lib/test/test_pathlib.py | 4 ++++ .../2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index e15718dc98d677..f3813e04109904 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -463,8 +463,12 @@ def _lines(self): try: return self._lines_cached except AttributeError: - trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] - self._lines_cached = str(self).translate(trans) + path_str = str(self) + if path_str == '.': + self._lines_cached = '' + else: + trans = _SWAP_SEP_AND_NEWLINE[self._flavour.sep] + self._lines_cached = path_str.translate(trans) return self._lines_cached def __eq__(self, other): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 464a835212d472..eb2b0cfb26e85f 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -384,6 +384,10 @@ def test_match_common(self): self.assertTrue(P('A.py').match('a.PY', case_sensitive=False)) self.assertFalse(P('c:/a/B.Py').match('C:/A/*.pY', case_sensitive=True)) self.assertTrue(P('/a/b/c.py').match('/A/*/*.Py', case_sensitive=False)) + # Matching against empty path + self.assertFalse(P().match('*')) + self.assertTrue(P().match('**')) + self.assertFalse(P().match('**/*')) def test_ordering_common(self): # Ordering is tuple-alike. diff --git a/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst new file mode 100644 index 00000000000000..c1f55ab658b517 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-02-10-56-41.gh-issue-106330.QSkIUH.rst @@ -0,0 +1,2 @@ +Fix incorrect matching of empty paths in :meth:`pathlib.PurePath.match`. +This bug was introduced in Python 3.12.0 beta 1. From 77090370952307730ea71d68b848cce0dc8cbd83 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 3 Jul 2023 15:38:38 -0500 Subject: [PATCH 246/446] Small speed-up for the convolve() recipe. (GH-106371) --- Doc/library/itertools.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 56d6599798af20..a2d1798a2c6da1 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1085,8 +1085,8 @@ The following recipes have a more mathematical flavor: kernel = tuple(kernel)[::-1] n = len(kernel) padded_signal = chain(repeat(0, n-1), signal, repeat(0, n-1)) - for window in sliding_window(padded_signal, n): - yield math.sumprod(kernel, window) + windowed_signal = sliding_window(padded_signal, n) + return map(math.sumprod, repeat(kernel), windowed_signal) def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. From 71b40443fed6acb58330ee262f8d674b394f41d3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 23:16:21 +0200 Subject: [PATCH 247/446] gh-104683: Modernise Argument Clinic parameter state machine (#106362) Use enums and pattern matching to make the code more readable. Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 129 +++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 51 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 41d4274fc744e0..6380b9ce38f5f6 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4294,6 +4294,37 @@ def dedent(self, line): StateKeeper = Callable[[str | None], None] ConverterArgs = dict[str, Any] +class ParamState(enum.IntEnum): + """Parameter parsing state. + + [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line + 01 2 3 4 5 6 <- state transitions + """ + # Before we've seen anything. + # Legal transitions: to LEFT_SQUARE_BEFORE or REQUIRED + START = 0 + + # Left square backets before required params. + LEFT_SQUARE_BEFORE = 1 + + # In a group, before required params. + GROUP_BEFORE = 2 + + # Required params, positional-or-keyword or positional-only (we + # don't know yet). Renumber left groups! + REQUIRED = 3 + + # Positional-or-keyword or positional-only params that now must have + # default values. + OPTIONAL = 4 + + # In a group, after required params. + GROUP_AFTER = 5 + + # Right square brackets after required params. + RIGHT_SQUARE_AFTER = 6 + + class DSLParser: function: Function | None state: StateKeeper @@ -4331,7 +4362,7 @@ def reset(self) -> None: self.keyword_only = False self.positional_only = False self.group = 0 - self.parameter_state = self.ps_start + self.parameter_state: ParamState = ParamState.START self.seen_positional_with_default = False self.indent = IndentStack() self.kind = CALLABLE @@ -4726,22 +4757,8 @@ def state_modulename_name(self, line: str | None) -> None: # # These rules are enforced with a single state variable: # "parameter_state". (Previously the code was a miasma of ifs and - # separate boolean state variables.) The states are: - # - # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line - # 01 2 3 4 5 6 <- state transitions - # - # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3. - # 1: ps_left_square_before. left square brackets before required parameters. - # 2: ps_group_before. in a group, before required parameters. - # 3: ps_required. required parameters, positional-or-keyword or positional-only - # (we don't know yet). (renumber left groups!) - # 4: ps_optional. positional-or-keyword or positional-only parameters that - # now must have default values. - # 5: ps_group_after. in a group, after required parameters. - # 6: ps_right_square_after. right square brackets after required parameters. - ps_start, ps_left_square_before, ps_group_before, ps_required, \ - ps_optional, ps_group_after, ps_right_square_after = range(7) + # separate boolean state variables.) The states are defined in the + # ParamState class. def state_parameters_start(self, line: str | None) -> None: if not self.valid_line(line): @@ -4759,8 +4776,8 @@ def to_required(self): """ Transition to the "required" parameter state. """ - if self.parameter_state != self.ps_required: - self.parameter_state = self.ps_required + if self.parameter_state is not ParamState.REQUIRED: + self.parameter_state = ParamState.REQUIRED for p in self.function.parameters.values(): p.group = -p.group @@ -4793,17 +4810,18 @@ def state_parameter(self, line): self.parse_special_symbol(line) return - if self.parameter_state in (self.ps_start, self.ps_required): - self.to_required() - elif self.parameter_state == self.ps_left_square_before: - self.parameter_state = self.ps_group_before - elif self.parameter_state == self.ps_group_before: - if not self.group: + match self.parameter_state: + case ParamState.START | ParamState.REQUIRED: self.to_required() - elif self.parameter_state in (self.ps_group_after, self.ps_optional): - pass - else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)") + case ParamState.LEFT_SQUARE_BEFORE: + self.parameter_state = ParamState.GROUP_BEFORE + case ParamState.GROUP_BEFORE: + if not self.group: + self.to_required() + case ParamState.GROUP_AFTER | ParamState.OPTIONAL: + pass + case st: + fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.a)") # handle "as" for parameters too c_name = None @@ -4863,8 +4881,9 @@ def state_parameter(self, line): name, legacy, kwargs = self.parse_converter(parameter.annotation) if not default: - if self.parameter_state == self.ps_optional: - fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!") + if self.parameter_state is ParamState.OPTIONAL: + fail(f"Can't have a parameter without a default ({parameter_name!r})\n" + "after a parameter with a default!") if is_vararg: value = NULL kwargs.setdefault('c_default', "NULL") @@ -4876,8 +4895,8 @@ def state_parameter(self, line): if is_vararg: fail("Vararg can't take a default value!") - if self.parameter_state == self.ps_required: - self.parameter_state = self.ps_optional + if self.parameter_state is ParamState.REQUIRED: + self.parameter_state = ParamState.OPTIONAL default = default.strip() bad = False ast_input = f"x = {default}" @@ -5001,14 +5020,14 @@ def bad_node(self, node): if isinstance(converter, self_converter): if len(self.function.parameters) == 1: - if (self.parameter_state != self.ps_required): + if self.parameter_state is not ParamState.REQUIRED: fail("A 'self' parameter cannot be marked optional.") if value is not unspecified: fail("A 'self' parameter cannot have a default value.") if self.group: fail("A 'self' parameter cannot be in an optional group.") kind = inspect.Parameter.POSITIONAL_ONLY - self.parameter_state = self.ps_start + self.parameter_state = ParamState.START self.function.parameters.clear() else: fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.") @@ -5016,7 +5035,7 @@ def bad_node(self, node): if isinstance(converter, defining_class_converter): _lp = len(self.function.parameters) if _lp == 1: - if (self.parameter_state != self.ps_required): + if self.parameter_state is not ParamState.REQUIRED: fail("A 'defining_class' parameter cannot be marked optional.") if value is not unspecified: fail("A 'defining_class' parameter cannot have a default value.") @@ -5065,12 +5084,13 @@ def parse_special_symbol(self, symbol): fail("Function " + self.function.name + " uses '*' more than once.") self.keyword_only = True elif symbol == '[': - if self.parameter_state in (self.ps_start, self.ps_left_square_before): - self.parameter_state = self.ps_left_square_before - elif self.parameter_state in (self.ps_required, self.ps_group_after): - self.parameter_state = self.ps_group_after - else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)") + match self.parameter_state: + case ParamState.START | ParamState.LEFT_SQUARE_BEFORE: + self.parameter_state = ParamState.LEFT_SQUARE_BEFORE + case ParamState.REQUIRED | ParamState.GROUP_AFTER: + self.parameter_state = ParamState.GROUP_AFTER + case st: + fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.b)") self.group += 1 self.function.docstring_only = True elif symbol == ']': @@ -5079,20 +5099,27 @@ def parse_special_symbol(self, symbol): if not any(p.group == self.group for p in self.function.parameters.values()): fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.") self.group -= 1 - if self.parameter_state in (self.ps_left_square_before, self.ps_group_before): - self.parameter_state = self.ps_group_before - elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after): - self.parameter_state = self.ps_right_square_after - else: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)") + match self.parameter_state: + case ParamState.LEFT_SQUARE_BEFORE | ParamState.GROUP_BEFORE: + self.parameter_state = ParamState.GROUP_BEFORE + case ParamState.GROUP_AFTER | ParamState.RIGHT_SQUARE_AFTER: + self.parameter_state = ParamState.RIGHT_SQUARE_AFTER + case st: + fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.c)") elif symbol == '/': if self.positional_only: fail("Function " + self.function.name + " uses '/' more than once.") self.positional_only = True - # ps_required and ps_optional are allowed here, that allows positional-only without option groups + # REQUIRED and OPTIONAL are allowed here, that allows positional-only without option groups # to work (and have default values!) - if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group: - fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)") + allowed = { + ParamState.REQUIRED, + ParamState.OPTIONAL, + ParamState.RIGHT_SQUARE_AFTER, + ParamState.GROUP_BEFORE, + } + if (self.parameter_state not in allowed) or self.group: + fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {self.parameter_state}.d)") if self.keyword_only: fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") # fixup preceding parameters From 3ee8dac7a1b3882aa3aac7703bdae2de7b6402ad Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 3 Jul 2023 23:57:20 +0200 Subject: [PATCH 248/446] gh-106368: Clean up Argument Clinic tests (#106373) --- Lib/test/test_clinic.py | 796 ++++++++++++++++++++++------------------ 1 file changed, 440 insertions(+), 356 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 51d2ac972752fd..b3602887ab6352 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -4,6 +4,7 @@ from test import support, test_tools from test.support import os_helper +from textwrap import dedent from unittest import TestCase import collections import inspect @@ -171,43 +172,43 @@ def test_solo_newline(self): def test_no_substitution(self): self._test(""" abc - """, """ + """, """ abc - """) + """) def test_empty_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc def - """, name='') + """, name='') def test_single_line_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc GARGLE def - """, name='GARGLE') + """, name='GARGLE') def test_multiline_substitution(self): self._test(""" abc {name} def - """, """ + """, """ abc bingle bungle def - """, name='bingle\nbungle\n') + """, name='bingle\nbungle\n') class InertParser: def __init__(self, clinic): @@ -240,9 +241,9 @@ def round_trip(self, input): def test_round_trip_1(self): self.round_trip(""" - verbatim text here - lah dee dah -""") + verbatim text here + lah dee dah + """) def test_round_trip_2(self): self.round_trip(""" verbatim text here @@ -286,22 +287,38 @@ def test_clinic_1(self): class ClinicParserTest(TestCase): + def checkDocstring(self, fn, expected): + self.assertTrue(hasattr(fn, "docstring")) + self.assertEqual(fn.docstring.strip(), + dedent(expected).strip()) + def test_trivial(self): parser = DSLParser(FakeClinic()) - block = clinic.Block("module os\nos.access") + block = clinic.Block(""" + module os + os.access + """) parser.parse(block) module, function = block.signatures self.assertEqual("access", function.name) self.assertEqual("os", module.name) def test_ignore_line(self): - block = self.parse("#\nmodule os\nos.access") + block = self.parse(dedent(""" + # + module os + os.access + """)) module, function = block.signatures self.assertEqual("access", function.name) self.assertEqual("os", module.name) def test_param(self): - function = self.parse_function("module os\nos.access\n path: int") + function = self.parse_function(""" + module os + os.access + path: int + """) self.assertEqual("access", function.name) self.assertEqual(2, len(function.parameters)) p = function.parameters['path'] @@ -309,236 +326,296 @@ def test_param(self): self.assertIsInstance(p.converter, clinic.int_converter) def test_param_default(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: bool = True") + function = self.parse_function(""" + module os + os.access + follow_symlinks: bool = True + """) p = function.parameters['follow_symlinks'] self.assertEqual(True, p.default) def test_param_with_continuations(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: \\\n bool \\\n =\\\n True") + function = self.parse_function(r""" + module os + os.access + follow_symlinks: \ + bool \ + = \ + True + """) p = function.parameters['follow_symlinks'] self.assertEqual(True, p.default) def test_param_default_expression(self): - function = self.parse_function("module os\nos.access\n follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize") + function = self.parse_function(""" + module os + os.access + follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize + """) p = function.parameters['follow_symlinks'] self.assertEqual(sys.maxsize, p.default) self.assertEqual("MAXSIZE", p.converter.c_default) - s = self.parse_function_should_fail("module os\nos.access\n follow_symlinks: int = sys.maxsize") - self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n") + expected_msg = ( + "Error on line 0:\n" + "When you specify a named constant ('sys.maxsize') as your default value,\n" + "you MUST specify a valid c_default.\n" + ) + out = self.parse_function_should_fail(""" + module os + os.access + follow_symlinks: int = sys.maxsize + """) + self.assertEqual(out, expected_msg) def test_param_no_docstring(self): function = self.parse_function(""" -module os -os.access - follow_symlinks: bool = True - something_else: str = ''""") + module os + os.access + follow_symlinks: bool = True + something_else: str = '' + """) p = function.parameters['follow_symlinks'] self.assertEqual(3, len(function.parameters)) - self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter) + conv = function.parameters['something_else'].converter + self.assertIsInstance(conv, clinic.str_converter) def test_param_default_parameters_out_of_order(self): - s = self.parse_function_should_fail(""" -module os -os.access - follow_symlinks: bool = True - something_else: str""") - self.assertEqual(s, """Error on line 0: -Can't have a parameter without a default ('something_else') -after a parameter with a default! -""") + expected_msg = ( + "Error on line 0:\n" + "Can't have a parameter without a default ('something_else')\n" + "after a parameter with a default!\n" + ) + out = self.parse_function_should_fail(""" + module os + os.access + follow_symlinks: bool = True + something_else: str""") + self.assertEqual(out, expected_msg) def disabled_test_converter_arguments(self): - function = self.parse_function("module os\nos.access\n path: path_t(allow_fd=1)") + function = self.parse_function(""" + module os + os.access + path: path_t(allow_fd=1) + """) p = function.parameters['path'] self.assertEqual(1, p.converter.args['allow_fd']) def test_function_docstring(self): function = self.parse_function(""" -module os -os.stat as os_stat_fn + module os + os.stat as os_stat_fn - path: str - Path to be examined + path: str + Path to be examined -Perform a stat system call on the given path.""") - self.assertEqual(""" -stat($module, /, path) --- + Perform a stat system call on the given path. + """) + self.checkDocstring(function, """ + stat($module, /, path) + -- -Perform a stat system call on the given path. + Perform a stat system call on the given path. - path - Path to be examined -""".strip(), function.docstring) + path + Path to be examined + """) def test_explicit_parameters_in_docstring(self): - function = self.parse_function(""" -module foo -foo.bar - x: int - Documentation for x. - y: int + function = self.parse_function(dedent(""" + module foo + foo.bar + x: int + Documentation for x. + y: int -This is the documentation for foo. + This is the documentation for foo. -Okay, we're done here. -""") - self.assertEqual(""" -bar($module, /, x, y) --- + Okay, we're done here. + """)) + self.checkDocstring(function, """ + bar($module, /, x, y) + -- -This is the documentation for foo. + This is the documentation for foo. - x - Documentation for x. + x + Documentation for x. -Okay, we're done here. -""".strip(), function.docstring) + Okay, we're done here. + """) def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self): - function = self.parse_function(""" -module os -os.stat - path: str -This/used to break Clinic! -""") - self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring) + function = self.parse_function(dedent(""" + module os + os.stat + path: str + This/used to break Clinic! + """)) + self.checkDocstring(function, """ + stat($module, /, path) + -- + + This/used to break Clinic! + """) def test_c_name(self): - function = self.parse_function("module os\nos.stat as os_stat_fn") + function = self.parse_function(""" + module os + os.stat as os_stat_fn + """) self.assertEqual("os_stat_fn", function.c_basename) def test_return_converter(self): - function = self.parse_function("module os\nos.stat -> int") + function = self.parse_function(""" + module os + os.stat -> int + """) self.assertIsInstance(function.return_converter, clinic.int_return_converter) def test_star(self): - function = self.parse_function("module os\nos.access\n *\n follow_symlinks: bool = True") + function = self.parse_function(""" + module os + os.access + * + follow_symlinks: bool = True + """) p = function.parameters['follow_symlinks'] self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind) self.assertEqual(0, p.group) def test_group(self): - function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n") + function = self.parse_function(""" + module window + window.border + [ + ls: int + ] + / + """) p = function.parameters['ls'] self.assertEqual(1, p.group) def test_left_group(self): function = self.parse_function(""" -module curses -curses.addch - [ - y: int - Y-coordinate. - x: int - X-coordinate. - ] - ch: char - Character to add. - [ - attr: long - Attributes for the character. - ] - / -""") - for name, group in ( + module curses + curses.addch + [ + y: int + Y-coordinate. + x: int + X-coordinate. + ] + ch: char + Character to add. + [ + attr: long + Attributes for the character. + ] + / + """) + dataset = ( ('y', -1), ('x', -1), ('ch', 0), ('attr', 1), - ): - p = function.parameters[name] - self.assertEqual(p.group, group) - self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - self.assertEqual(function.docstring.strip(), """ -addch([y, x,] ch, [attr]) - - - y - Y-coordinate. - x - X-coordinate. - ch - Character to add. - attr - Attributes for the character. - """.strip()) + ) + for name, group in dataset: + with self.subTest(name=name, group=group): + p = function.parameters[name] + self.assertEqual(p.group, group) + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + self.checkDocstring(function, """ + addch([y, x,] ch, [attr]) + + + y + Y-coordinate. + x + X-coordinate. + ch + Character to add. + attr + Attributes for the character. + """) def test_nested_groups(self): function = self.parse_function(""" -module curses -curses.imaginary - [ - [ - y1: int - Y-coordinate. - y2: int - Y-coordinate. - ] - x1: int - X-coordinate. - x2: int - X-coordinate. - ] - ch: char - Character to add. - [ - attr1: long - Attributes for the character. - attr2: long - Attributes for the character. - attr3: long - Attributes for the character. - [ - attr4: long - Attributes for the character. - attr5: long - Attributes for the character. - attr6: long - Attributes for the character. - ] - ] - / -""") - for name, group in ( + module curses + curses.imaginary + [ + [ + y1: int + Y-coordinate. + y2: int + Y-coordinate. + ] + x1: int + X-coordinate. + x2: int + X-coordinate. + ] + ch: char + Character to add. + [ + attr1: long + Attributes for the character. + attr2: long + Attributes for the character. + attr3: long + Attributes for the character. + [ + attr4: long + Attributes for the character. + attr5: long + Attributes for the character. + attr6: long + Attributes for the character. + ] + ] + / + """) + dataset = ( ('y1', -2), ('y2', -2), ('x1', -1), ('x2', -1), ('ch', 0), ('attr1', 1), ('attr2', 1), ('attr3', 1), ('attr4', 2), ('attr5', 2), ('attr6', 2), - ): - p = function.parameters[name] - self.assertEqual(p.group, group) - self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) - - self.assertEqual(function.docstring.strip(), """ -imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, - attr6]]) - - - y1 - Y-coordinate. - y2 - Y-coordinate. - x1 - X-coordinate. - x2 - X-coordinate. - ch - Character to add. - attr1 - Attributes for the character. - attr2 - Attributes for the character. - attr3 - Attributes for the character. - attr4 - Attributes for the character. - attr5 - Attributes for the character. - attr6 - Attributes for the character. - """.strip()) + ) + for name, group in dataset: + with self.subTest(name=name, group=group): + p = function.parameters[name] + self.assertEqual(p.group, group) + self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY) + + self.checkDocstring(function, """ + imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5, + attr6]]) + + + y1 + Y-coordinate. + y2 + Y-coordinate. + x1 + X-coordinate. + x2 + X-coordinate. + ch + Character to add. + attr1 + Attributes for the character. + attr2 + Attributes for the character. + attr3 + Attributes for the character. + attr4 + Attributes for the character. + attr5 + Attributes for the character. + attr6 + Attributes for the character. + """) def parse_function_should_fail(self, s): with support.captured_stdout() as stdout: @@ -547,104 +624,108 @@ def parse_function_should_fail(self, s): return stdout.getvalue() def test_disallowed_grouping__two_top_groups_on_left(self): - s = self.parse_function_should_fail(""" -module foo -foo.two_top_groups_on_left - [ - group1 : int - ] - [ - group2 : int - ] - param: int - """) - self.assertEqual(s, - ('Error on line 0:\n' - 'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n')) + expected_msg = ( + 'Error on line 0:\n' + 'Function two_top_groups_on_left has an unsupported group ' + 'configuration. (Unexpected state 2.b)\n' + ) + out = self.parse_function_should_fail(""" + module foo + foo.two_top_groups_on_left + [ + group1 : int + ] + [ + group2 : int + ] + param: int + """) + self.assertEqual(out, expected_msg) def test_disallowed_grouping__two_top_groups_on_right(self): self.parse_function_should_fail(""" -module foo -foo.two_top_groups_on_right - param: int - [ - group1 : int - ] - [ - group2 : int - ] - """) + module foo + foo.two_top_groups_on_right + param: int + [ + group1 : int + ] + [ + group2 : int + ] + """) def test_disallowed_grouping__parameter_after_group_on_right(self): self.parse_function_should_fail(""" -module foo -foo.parameter_after_group_on_right - param: int - [ - [ - group1 : int - ] - group2 : int - ] - """) + module foo + foo.parameter_after_group_on_right + param: int + [ + [ + group1 : int + ] + group2 : int + ] + """) def test_disallowed_grouping__group_after_parameter_on_left(self): self.parse_function_should_fail(""" -module foo -foo.group_after_parameter_on_left - [ - group2 : int - [ - group1 : int - ] - ] - param: int - """) + module foo + foo.group_after_parameter_on_left + [ + group2 : int + [ + group1 : int + ] + ] + param: int + """) def test_disallowed_grouping__empty_group_on_left(self): self.parse_function_should_fail(""" -module foo -foo.empty_group - [ - [ - ] - group2 : int - ] - param: int - """) + module foo + foo.empty_group + [ + [ + ] + group2 : int + ] + param: int + """) def test_disallowed_grouping__empty_group_on_right(self): self.parse_function_should_fail(""" -module foo -foo.empty_group - param: int - [ - [ - ] - group2 : int - ] - """) + module foo + foo.empty_group + param: int + [ + [ + ] + group2 : int + ] + """) def test_no_parameters(self): function = self.parse_function(""" -module foo -foo.bar + module foo + foo.bar -Docstring + Docstring -""") + """) self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring) self.assertEqual(1, len(function.parameters)) # self! def test_init_with_no_parameters(self): function = self.parse_function(""" -module foo -class foo.Bar "unused" "notneeded" -foo.Bar.__init__ + module foo + class foo.Bar "unused" "notneeded" + foo.Bar.__init__ -Docstring + Docstring + + """, signatures_in_block=3, function_index=2) -""", signatures_in_block=3, function_index=2) # self is not in the signature self.assertEqual("Bar()\n--\n\nDocstring", function.docstring) # but it *is* a parameter @@ -652,113 +733,117 @@ class foo.Bar "unused" "notneeded" def test_illegal_module_line(self): self.parse_function_should_fail(""" -module foo -foo.bar => int - / -""") + module foo + foo.bar => int + / + """) def test_illegal_c_basename(self): self.parse_function_should_fail(""" -module foo -foo.bar as 935 - / -""") + module foo + foo.bar as 935 + / + """) def test_single_star(self): self.parse_function_should_fail(""" -module foo -foo.bar - * - * -""") + module foo + foo.bar + * + * + """) def test_parameters_required_after_star_without_initial_parameters_or_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - * -""") + module foo + foo.bar + * + """) def test_parameters_required_after_star_without_initial_parameters_with_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - * -Docstring here. -""") + module foo + foo.bar + * + Docstring here. + """) def test_parameters_required_after_star_with_initial_parameters_without_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - this: int - * -""") + module foo + foo.bar + this: int + * + """) def test_parameters_required_after_star_with_initial_parameters_and_docstring(self): self.parse_function_should_fail(""" -module foo -foo.bar - this: int - * -Docstring. -""") + module foo + foo.bar + this: int + * + Docstring. + """) def test_single_slash(self): self.parse_function_should_fail(""" -module foo -foo.bar - / - / -""") + module foo + foo.bar + / + / + """) def test_mix_star_and_slash(self): self.parse_function_should_fail(""" -module foo -foo.bar - x: int - y: int - * - z: int - / -""") + module foo + foo.bar + x: int + y: int + * + z: int + / + """) def test_parameters_not_permitted_after_slash_for_now(self): self.parse_function_should_fail(""" -module foo -foo.bar - / - x: int -""") + module foo + foo.bar + / + x: int + """) def test_parameters_no_more_than_one_vararg(self): - s = self.parse_function_should_fail(""" -module foo -foo.bar - *vararg1: object - *vararg2: object -""") - self.assertEqual(s, "Error on line 0:\nToo many var args\n") + expected_msg = ( + "Error on line 0:\n" + "Too many var args\n" + ) + out = self.parse_function_should_fail(""" + module foo + foo.bar + *vararg1: object + *vararg2: object + """) + self.assertEqual(out, expected_msg) def test_function_not_at_column_0(self): function = self.parse_function(""" - module foo - foo.bar - x: int - Nested docstring here, goeth. - * - y: str - Not at column 0! -""") - self.assertEqual(""" -bar($module, /, x, *, y) --- + module foo + foo.bar + x: int + Nested docstring here, goeth. + * + y: str + Not at column 0! + """) + self.checkDocstring(function, """ + bar($module, /, x, *, y) + -- -Not at column 0! + Not at column 0! - x - Nested docstring here, goeth. -""".strip(), function.docstring) + x + Nested docstring here, goeth. + """) def test_directive(self): c = FakeClinic() @@ -772,46 +857,39 @@ def test_directive(self): def test_legacy_converters(self): block = self.parse('module os\nos.access\n path: "s"') module, function = block.signatures - self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter) + conv = (function.parameters['path']).converter + self.assertIsInstance(conv, clinic.str_converter) def test_legacy_converters_non_string_constant_annotation(self): - expected_failure_message = """\ -Error on line 0: -Annotations must be either a name, a function call, or a string. -""" - - s = self.parse_function_should_fail('module os\nos.access\n path: 42') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: 42.42') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: 42j') - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail('module os\nos.access\n path: b"42"') - self.assertEqual(s, expected_failure_message) - - def test_other_bizarre_things_in_annotations_fail(self): - expected_failure_message = """\ -Error on line 0: -Annotations must be either a name, a function call, or a string. -""" - - s = self.parse_function_should_fail( - 'module os\nos.access\n path: {"some": "dictionary"}' + expected_failure_message = ( + "Error on line 0:\n" + "Annotations must be either a name, a function call, or a string.\n" ) - self.assertEqual(s, expected_failure_message) - - s = self.parse_function_should_fail( - 'module os\nos.access\n path: ["list", "of", "strings"]' + dataset = ( + 'module os\nos.access\n path: 42', + 'module os\nos.access\n path: 42.42', + 'module os\nos.access\n path: 42j', + 'module os\nos.access\n path: b"42"', ) - self.assertEqual(s, expected_failure_message) + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_failure_message) - s = self.parse_function_should_fail( - 'module os\nos.access\n path: (x for x in range(42))' + def test_other_bizarre_things_in_annotations_fail(self): + expected_failure_message = ( + "Error on line 0:\n" + "Annotations must be either a name, a function call, or a string.\n" + ) + dataset = ( + 'module os\nos.access\n path: {"some": "dictionary"}', + 'module os\nos.access\n path: ["list", "of", "strings"]', + 'module os\nos.access\n path: (x for x in range(42))', ) - self.assertEqual(s, expected_failure_message) + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertEqual(out, expected_failure_message) def test_kwarg_splats_disallowed_in_function_call_annotations(self): expected_error_msg = ( @@ -945,10 +1023,16 @@ def test_scaffolding(self): self.assertEqual(repr(clinic.NULL), '') # test that fail fails + expected = ( + 'Error in file "clown.txt" on line 69:\n' + 'The igloos are melting!\n' + ) with support.captured_stdout() as stdout: with self.assertRaises(SystemExit): - clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69) - self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n') + clinic.fail('The igloos are melting!', + filename='clown.txt', line_number=69) + actual = stdout.getvalue() + self.assertEqual(actual, expected) class ClinicExternalTest(TestCase): From b24479dcba6e8952039066564d448d5ac4b37bef Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 4 Jul 2023 00:10:46 +0200 Subject: [PATCH 249/446] gh-104050: Annotate more Argument Clinic DSLParser state methods (#106376) Annotate the following methods: - state_parameter() - state_parameter_docstring_start() Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 6380b9ce38f5f6..a07fcbd8cabf76 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4781,14 +4781,16 @@ def to_required(self): for p in self.function.parameters.values(): p.group = -p.group - def state_parameter(self, line): - if self.parameter_continuation: - line = self.parameter_continuation + ' ' + line.lstrip() - self.parameter_continuation = '' + def state_parameter(self, line: str | None) -> None: + assert isinstance(self.function, Function) if not self.valid_line(line): return + if self.parameter_continuation: + line = self.parameter_continuation + ' ' + line.lstrip() + self.parameter_continuation = '' + assert self.indent.depth == 2 indent = self.indent.infer(line) if indent == -1: @@ -4839,6 +4841,7 @@ def state_parameter(self, line): fields[0] = name line = ' '.join(fields) + default: str | None base, equals, default = line.rpartition('=') if not equals: base = default @@ -4861,7 +4864,9 @@ def state_parameter(self, line): if not module: fail("Function " + self.function.name + " has an invalid parameter declaration:\n\t" + line) - function_args = module.body[0].args + function = module.body[0] + assert isinstance(function, ast.FunctionDef) + function_args = function.args if len(function_args.args) > 1: fail("Function " + self.function.name + " has an invalid parameter declaration (comma?):\n\t" + line) @@ -4884,6 +4889,7 @@ def state_parameter(self, line): if self.parameter_state is ParamState.OPTIONAL: fail(f"Can't have a parameter without a default ({parameter_name!r})\n" "after a parameter with a default!") + value: Sentinels | Null if is_vararg: value = NULL kwargs.setdefault('c_default', "NULL") @@ -4946,8 +4952,11 @@ def bad_node(self, node): if bad: fail("Unsupported expression as default value: " + repr(default)) - expr = module.body[0].value + assignment = module.body[0] + assert isinstance(assignment, ast.Assign) + expr = assignment.value # mild hack: explicitly support NULL as a default value + c_default: str | None if isinstance(expr, ast.Name) and expr.id == 'NULL': value = NULL py_default = '' @@ -4964,7 +4973,7 @@ def bad_node(self, node): value = unknown elif isinstance(expr, ast.Attribute): a = [] - n = expr + n: ast.expr | ast.Attribute = expr while isinstance(n, ast.Attribute): a.append(n.attr) n = n.value @@ -4984,7 +4993,7 @@ def bad_node(self, node): else: value = ast.literal_eval(expr) py_default = repr(value) - if isinstance(value, (bool, None.__class__)): + if isinstance(value, (bool, NoneType)): c_default = "Py_" + py_default elif isinstance(value, str): c_default = c_repr(value) @@ -5011,6 +5020,7 @@ def bad_node(self, node): # but the parameter object gets the python name converter = dict[name](c_name or parameter_name, parameter_name, self.function, value, **kwargs) + kind: inspect._ParameterKind if is_vararg: kind = inspect.Parameter.VAR_POSITIONAL elif self.keyword_only: @@ -5130,7 +5140,7 @@ def parse_special_symbol(self, symbol): fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") p.kind = inspect.Parameter.POSITIONAL_ONLY - def state_parameter_docstring_start(self, line: str) -> None: + def state_parameter_docstring_start(self, line: str | None) -> None: self.parameter_docstring_indent = len(self.indent.margin) assert self.indent.depth == 3 return self.next(self.state_parameter_docstring, line) From 506cfdf141f03186d5cdf9bb31caa40294eba4e5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 00:35:46 +0200 Subject: [PATCH 250/446] gh-106320: Remove more private _PyUnicode C API functions (#106382) Remove more private _PyUnicode C API functions: move them to the internal C API (pycore_unicodeobject.h). No longer export most pycore_unicodeobject.h functions. --- Include/cpython/unicodeobject.h | 69 ------------------------ Include/internal/pycore_unicodeobject.h | 70 ++++++++++++++++++++++++- Python/future.c | 1 + 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index c5892a80d2c54d..fcd9c28e030c1f 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -394,11 +394,6 @@ static inline int PyUnicode_READY(PyObject* Py_UNUSED(op)) } #define PyUnicode_READY(op) PyUnicode_READY(_PyObject_CAST(op)) -/* Get a copy of a Unicode string. */ -PyAPI_FUNC(PyObject*) _PyUnicode_Copy( - PyObject *unicode - ); - /* Copy character from one unicode object into another, this function performs character conversion when necessary and falls back to memcpy() if possible. @@ -425,17 +420,6 @@ PyAPI_FUNC(Py_ssize_t) PyUnicode_CopyCharacters( Py_ssize_t how_many ); -/* Unsafe version of PyUnicode_CopyCharacters(): don't check arguments and so - may crash if parameters are invalid (e.g. if the output string - is too short). */ -PyAPI_FUNC(void) _PyUnicode_FastCopyCharacters( - PyObject *to, - Py_ssize_t to_start, - PyObject *from, - Py_ssize_t from_start, - Py_ssize_t how_many - ); - /* Fill a string with a character: write fill_char into unicode[start:start+length]. @@ -451,15 +435,6 @@ PyAPI_FUNC(Py_ssize_t) PyUnicode_Fill( Py_UCS4 fill_char ); -/* Unsafe version of PyUnicode_Fill(): don't check arguments and so may crash - if parameters are invalid (e.g. if length is longer than the string). */ -PyAPI_FUNC(void) _PyUnicode_FastFill( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t length, - Py_UCS4 fill_char - ); - /* Create a new string from a buffer of Py_UCS1, Py_UCS2 or Py_UCS4 characters. Scan the string to find the maximum character. */ PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData( @@ -467,19 +442,6 @@ PyAPI_FUNC(PyObject*) PyUnicode_FromKindAndData( const void *buffer, Py_ssize_t size); -/* Create a new string from a buffer of ASCII characters. - WARNING: Don't check if the string contains any non-ASCII character. */ -PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII( - const char *buffer, - Py_ssize_t size); - -/* Compute the maximum character of the substring unicode[start:end]. - Return 127 for an empty string. */ -PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( - PyObject *unicode, - Py_ssize_t start, - Py_ssize_t end); - /* --- Manage the default encoding ---------------------------------------- */ /* Returns a pointer to the default encoding (UTF-8) of the @@ -618,37 +580,6 @@ PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( PyObject *unicode /* Unicode object */ ); -/* --- Methods & Slots ---------------------------------------------------- */ - -PyAPI_FUNC(PyObject *) _PyUnicode_JoinArray( - PyObject *separator, - PyObject *const *items, - Py_ssize_t seqlen - ); - -/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, - 0 otherwise. The right argument must be ASCII identifier. - Any error occurs inside will be cleared before return. */ -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIId( - PyObject *left, /* Left string */ - _Py_Identifier *right /* Right identifier */ - ); - -/* Test whether a unicode is equal to ASCII string. Return 1 if true, - 0 otherwise. The right argument must be ASCII-encoded string. - Any error occurs inside will be cleared before return. */ -PyAPI_FUNC(int) _PyUnicode_EqualToASCIIString( - PyObject *left, - const char *right /* ASCII-encoded string */ - ); - -/* Externally visible for str.strip(unicode) */ -PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( - PyObject *self, - int striptype, - PyObject *sepobj - ); - /* === Characters Type APIs =============================================== */ /* These should not be used directly. Use the Py_UNICODE_IS* and diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index a8c7f1957f3600..da01f57f962793 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -14,6 +14,44 @@ extern "C" { void _PyUnicode_ExactDealloc(PyObject *op); Py_ssize_t _PyUnicode_InternedSize(void); +/* Get a copy of a Unicode string. */ +PyAPI_FUNC(PyObject*) _PyUnicode_Copy( + PyObject *unicode + ); + +/* Unsafe version of PyUnicode_Fill(): don't check arguments and so may crash + if parameters are invalid (e.g. if length is longer than the string). */ +extern void _PyUnicode_FastFill( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t length, + Py_UCS4 fill_char + ); + +/* Unsafe version of PyUnicode_CopyCharacters(): don't check arguments and so + may crash if parameters are invalid (e.g. if the output string + is too short). */ +extern void _PyUnicode_FastCopyCharacters( + PyObject *to, + Py_ssize_t to_start, + PyObject *from, + Py_ssize_t from_start, + Py_ssize_t how_many + ); + +/* Create a new string from a buffer of ASCII characters. + WARNING: Don't check if the string contains any non-ASCII character. */ +extern PyObject* _PyUnicode_FromASCII( + const char *buffer, + Py_ssize_t size); + +/* Compute the maximum character of the substring unicode[start:end]. + Return 127 for an empty string. */ +extern Py_UCS4 _PyUnicode_FindMaxChar ( + PyObject *unicode, + Py_ssize_t start, + Py_ssize_t end); + /* --- _PyUnicodeWriter API ----------------------------------------------- */ typedef struct { @@ -141,10 +179,40 @@ PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( /* --- Methods & Slots ---------------------------------------------------- */ +extern PyObject* _PyUnicode_JoinArray( + PyObject *separator, + PyObject *const *items, + Py_ssize_t seqlen + ); + +/* Test whether a unicode is equal to ASCII identifier. Return 1 if true, + 0 otherwise. The right argument must be ASCII identifier. + Any error occurs inside will be cleared before return. */ +extern int _PyUnicode_EqualToASCIIId( + PyObject *left, /* Left string */ + _Py_Identifier *right /* Right identifier */ + ); + +/* Test whether a unicode is equal to ASCII string. Return 1 if true, + 0 otherwise. The right argument must be ASCII-encoded string. + Any error occurs inside will be cleared before return. */ +PyAPI_FUNC(int) _PyUnicode_EqualToASCIIString( + PyObject *left, + const char *right /* ASCII-encoded string */ + ); + +/* Externally visible for str.strip(unicode) */ +extern PyObject* _PyUnicode_XStrip( + PyObject *self, + int striptype, + PyObject *sepobj + ); + + /* Using explicit passed-in values, insert the thousands grouping into the string pointed to by buffer. For the argument descriptions, see Objects/stringlib/localeutil.h */ -PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping( +extern Py_ssize_t _PyUnicode_InsertThousandsGrouping( _PyUnicodeWriter *writer, Py_ssize_t n_buffer, PyObject *digits, diff --git a/Python/future.c b/Python/future.c index d56f7330964684..0dbc7ede20f324 100644 --- a/Python/future.c +++ b/Python/future.c @@ -1,5 +1,6 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() +#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString() #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" From f6d2bb18aba844f6bb5836797c72eb791b7f3644 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 00:52:27 +0200 Subject: [PATCH 251/446] gh-86085: Remove _PyCodec_Forget() declaration (#106377) The code was already removed by: commit c9f696cb96d1c362d5cad871f61da520572d9b08. --- Include/internal/pycore_codecs.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Include/internal/pycore_codecs.h b/Include/internal/pycore_codecs.h index 2f8d9d510019ba..a2465192eacd5e 100644 --- a/Include/internal/pycore_codecs.h +++ b/Include/internal/pycore_codecs.h @@ -6,8 +6,6 @@ extern "C" { extern PyObject* _PyCodec_Lookup(const char *encoding); -extern int _PyCodec_Forget(const char *encoding); - /* Text codec specific encoding and decoding API. Checks the encoding against a list of codecs which do not From 2e92edbf6de9578b30cca8e48c4bfb2ba71ae97a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 01:02:07 +0200 Subject: [PATCH 252/446] gh-106320: Remove private _PyImport C API functions (#106383) * Remove private _PyImport C API functions: move them to the internal C API (pycore_import.h). * No longer export most of these private functions. * _testcapi avoids private _PyImport_GetModuleAttrString(). --- Include/cpython/import.h | 20 -------------------- Include/internal/pycore_import.h | 20 ++++++++++++++++++++ Modules/_elementtree.c | 5 +++++ Modules/_sqlite/connection.c | 1 + Modules/_sqlite/module.c | 6 ++++++ Modules/_testcapimodule.c | 10 ++++++++-- Modules/cjkcodecs/cjkcodecs.h | 1 + Modules/pyexpat.c | 5 +++++ 8 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Include/cpython/import.h b/Include/cpython/import.h index 2bca4ade4c4f2c..cdfdd15bfa48d2 100644 --- a/Include/cpython/import.h +++ b/Include/cpython/import.h @@ -4,23 +4,6 @@ PyMODINIT_FUNC PyInit__imp(void); -PyAPI_FUNC(int) _PyImport_IsInitialized(PyInterpreterState *); - -PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(_Py_Identifier *name); -PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module); -PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module); - -PyAPI_FUNC(void) _PyImport_AcquireLock(PyInterpreterState *interp); -PyAPI_FUNC(int) _PyImport_ReleaseLock(PyInterpreterState *interp); - -PyAPI_FUNC(int) _PyImport_FixupBuiltin( - PyObject *mod, - const char *name, /* UTF-8 encoded string */ - PyObject *modules - ); -PyAPI_FUNC(int) _PyImport_FixupExtensionObject(PyObject*, PyObject *, - PyObject *, PyObject *); - struct _inittab { const char *name; /* ASCII encoded string */ PyObject* (*initfunc)(void); @@ -41,6 +24,3 @@ struct _frozen { collection of frozen modules: */ PyAPI_DATA(const struct _frozen *) PyImport_FrozenModules; - -PyAPI_DATA(PyObject *) _PyImport_GetModuleAttr(PyObject *, PyObject *); -PyAPI_DATA(PyObject *) _PyImport_GetModuleAttrString(const char *, const char *); diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index ee93f7d99d9155..457a654aff4644 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -7,6 +7,26 @@ extern "C" { #include "pycore_time.h" // _PyTime_t +extern int _PyImport_IsInitialized(PyInterpreterState *); + +PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(_Py_Identifier *name); +PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module); +PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module); + +extern void _PyImport_AcquireLock(PyInterpreterState *interp); +extern int _PyImport_ReleaseLock(PyInterpreterState *interp); + +extern int _PyImport_FixupBuiltin( + PyObject *mod, + const char *name, /* UTF-8 encoded string */ + PyObject *modules + ); +extern int _PyImport_FixupExtensionObject(PyObject*, PyObject *, + PyObject *, PyObject *); + +PyAPI_DATA(PyObject *) _PyImport_GetModuleAttr(PyObject *, PyObject *); +PyAPI_DATA(PyObject *) _PyImport_GetModuleAttrString(const char *, const char *); + struct _import_runtime_state { /* The builtin modules (defined in config.c). */ diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 48280690a707a4..3e742e067e7db1 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -11,7 +11,12 @@ *-------------------------------------------------------------------- */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" +#include "pycore_import.h" // _PyImport_GetModuleAttrString() #include "structmember.h" // PyMemberDef #include "expat.h" #include "pyexpat.h" diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 967ba2812080e5..d71cef14779e51 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -33,6 +33,7 @@ #include "blob.h" #include "prepare_protocol.h" #include "util.h" +#include "pycore_import.h" // _PyImport_GetModuleAttrString() #include "pycore_weakref.h" // _PyWeakref_IS_DEAD() #include diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index ea4d8c58b7ee0e..368e581b4f3355 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -21,6 +21,10 @@ * 3. This notice may not be removed or altered from any source distribution. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "connection.h" #include "statement.h" #include "cursor.h" @@ -29,6 +33,8 @@ #include "row.h" #include "blob.h" +#include "pycore_import.h" // _PyImport_GetModuleAttrString() + #if SQLITE_VERSION_NUMBER < 3015002 #error "SQLite 3.15.2 or higher required" #endif diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ce1131743eb2a4..d1044b5445202d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1267,9 +1267,15 @@ test_pep3118_obsolete_write_locks(PyObject* self, PyObject *Py_UNUSED(ignored)) if (ret != -1 || match == 0) goto error; + PyObject *mod_io = PyImport_ImportModule("_io"); + if (mod_io == NULL) { + return NULL; + } + /* bytesiobuf_getbuffer() */ - PyTypeObject *type = (PyTypeObject *)_PyImport_GetModuleAttrString( - "_io", "_BytesIOBuffer"); + PyTypeObject *type = (PyTypeObject *)PyObject_GetAttrString( + mod_io, "_BytesIOBuffer"); + Py_DECREF(mod_io); if (type == NULL) { return NULL; } diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index 97290aac3ba439..ee588785e7403f 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -13,6 +13,7 @@ #include "Python.h" #include "multibytecodec.h" +#include "pycore_import.h" // _PyImport_GetModuleAttrString() /* a unicode "undefined" code point */ diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index e3333fff00b2b2..28915359fb49e2 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1,4 +1,9 @@ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" +#include "pycore_import.h" // _PyImport_SetModule() #include #include "structmember.h" // PyMemberDef From 648688c137744a623a71dc2413d2879b80c99eae Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 4 Jul 2023 01:10:47 +0200 Subject: [PATCH 253/446] gh-106368: Harden Argument Clinic parser tests (#106384) --- Lib/test/test_clinic.py | 110 +++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 42 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b3602887ab6352..c5cfe53e0df99b 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -643,7 +643,7 @@ def test_disallowed_grouping__two_top_groups_on_left(self): self.assertEqual(out, expected_msg) def test_disallowed_grouping__two_top_groups_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.two_top_groups_on_right param: int @@ -654,9 +654,14 @@ def test_disallowed_grouping__two_top_groups_on_right(self): group2 : int ] """) + msg = ( + "Function two_top_groups_on_right has an unsupported group " + "configuration. (Unexpected state 6.b)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__parameter_after_group_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.parameter_after_group_on_right param: int @@ -667,9 +672,14 @@ def test_disallowed_grouping__parameter_after_group_on_right(self): group2 : int ] """) + msg = ( + "Function parameter_after_group_on_right has an unsupported group " + "configuration. (Unexpected state 6.a)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__group_after_parameter_on_left(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.group_after_parameter_on_left [ @@ -680,9 +690,14 @@ def test_disallowed_grouping__group_after_parameter_on_left(self): ] param: int """) + msg = ( + "Function group_after_parameter_on_left has an unsupported group " + "configuration. (Unexpected state 2.b)" + ) + self.assertIn(msg, out) def test_disallowed_grouping__empty_group_on_left(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.empty_group [ @@ -692,9 +707,14 @@ def test_disallowed_grouping__empty_group_on_left(self): ] param: int """) + msg = ( + "Function empty_group has an empty group.\n" + "All groups must contain at least one parameter." + ) + self.assertIn(msg, out) def test_disallowed_grouping__empty_group_on_right(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.empty_group param: int @@ -704,6 +724,11 @@ def test_disallowed_grouping__empty_group_on_right(self): group2 : int ] """) + msg = ( + "Function empty_group has an empty group.\n" + "All groups must contain at least one parameter." + ) + self.assertIn(msg, out) def test_no_parameters(self): function = self.parse_function(""" @@ -732,69 +757,60 @@ class foo.Bar "unused" "notneeded" self.assertEqual(1, len(function.parameters)) def test_illegal_module_line(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar => int / """) + msg = "Illegal function name: foo.bar => int" + self.assertIn(msg, out) def test_illegal_c_basename(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar as 935 / """) + msg = "Illegal C basename: 935" + self.assertIn(msg, out) def test_single_star(self): - self.parse_function_should_fail(""" - module foo - foo.bar - * - * - """) - - def test_parameters_required_after_star_without_initial_parameters_or_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - * - """) - - def test_parameters_required_after_star_without_initial_parameters_with_docstring(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar * - Docstring here. - """) - - def test_parameters_required_after_star_with_initial_parameters_without_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - this: int * """) + self.assertIn("Function bar uses '*' more than once.", out) - def test_parameters_required_after_star_with_initial_parameters_and_docstring(self): - self.parse_function_should_fail(""" - module foo - foo.bar - this: int - * - Docstring. - """) + def test_parameters_required_after_star(self): + dataset = ( + "module foo\nfoo.bar\n *", + "module foo\nfoo.bar\n *\nDocstring here.", + "module foo\nfoo.bar\n this: int\n *", + "module foo\nfoo.bar\n this: int\n *\nDocstring.", + ) + msg = "Function bar specifies '*' without any parameters afterwards." + for block in dataset: + with self.subTest(block=block): + out = self.parse_function_should_fail(block) + self.assertIn(msg, out) def test_single_slash(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar / / """) + msg = ( + "Function bar has an unsupported group configuration. " + "(Unexpected state 0.d)" + ) + self.assertIn(msg, out) def test_mix_star_and_slash(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar x: int @@ -803,14 +819,24 @@ def test_mix_star_and_slash(self): z: int / """) + msg = ( + "Function bar mixes keyword-only and positional-only parameters, " + "which is unsupported." + ) + self.assertIn(msg, out) def test_parameters_not_permitted_after_slash_for_now(self): - self.parse_function_should_fail(""" + out = self.parse_function_should_fail(""" module foo foo.bar / x: int """) + msg = ( + "Function bar has an unsupported group configuration. " + "(Unexpected state 0.d)" + ) + self.assertIn(msg, out) def test_parameters_no_more_than_one_vararg(self): expected_msg = ( From b4256135809d78d342e9d92e8bc3f527d3d3057f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 01:37:48 +0200 Subject: [PATCH 254/446] gh-106320: Fix _PyImport_GetModuleAttr() declaration (#106386) Replace PyAPI_DATA() with PyAPI_FUNC(). --- Include/internal/pycore_import.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 457a654aff4644..c048ae88d9000c 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -24,8 +24,8 @@ extern int _PyImport_FixupBuiltin( extern int _PyImport_FixupExtensionObject(PyObject*, PyObject *, PyObject *, PyObject *); -PyAPI_DATA(PyObject *) _PyImport_GetModuleAttr(PyObject *, PyObject *); -PyAPI_DATA(PyObject *) _PyImport_GetModuleAttrString(const char *, const char *); +PyAPI_FUNC(PyObject *) _PyImport_GetModuleAttr(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyImport_GetModuleAttrString(const char *, const char *); struct _import_runtime_state { From 3406f8cce542ea4edf4153c0fac5216df283a9b1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 4 Jul 2023 01:58:27 +0200 Subject: [PATCH 255/446] gh-106368: Increase Argument Clinic test coverage (#106389) Add: - test_disallowed_gropuing__no_matching_bracket - test_double_slash --- Lib/test/test_clinic.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c5cfe53e0df99b..03754d0bf123be 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -730,6 +730,18 @@ def test_disallowed_grouping__empty_group_on_right(self): ) self.assertIn(msg, out) + def test_disallowed_grouping__no_matching_bracket(self): + out = self.parse_function_should_fail(""" + module foo + foo.empty_group + param: int + ] + group2: int + ] + """) + msg = "Function empty_group has a ] without a matching [." + self.assertIn(msg, out) + def test_no_parameters(self): function = self.parse_function(""" module foo @@ -809,6 +821,18 @@ def test_single_slash(self): ) self.assertIn(msg, out) + def test_double_slash(self): + out = self.parse_function_should_fail(""" + module foo + foo.bar + a: int + / + b: int + / + """) + msg = "Function bar uses '/' more than once." + self.assertIn(msg, out) + def test_mix_star_and_slash(self): out = self.parse_function_should_fail(""" module foo From d8c5d76da2d5c3e8f9c05fcfc59dc1aaaa1fe6e1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 09:29:52 +0200 Subject: [PATCH 256/446] gh-106320: Remove private _PyUnicode codecs C API functions (#106385) Remove private _PyUnicode codecs C API functions: move them to the internal C API (pycore_unicodeobject.h). No longer export most of these functions. --- Include/cpython/unicodeobject.h | 106 ------------------------ Include/internal/pycore_unicodeobject.h | 100 ++++++++++++++++++++++ Parser/string_parser.c | 1 + 3 files changed, 101 insertions(+), 106 deletions(-) diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index fcd9c28e030c1f..dc8f6437c0e2c4 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -461,112 +461,6 @@ PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); #define _PyUnicode_AsString PyUnicode_AsUTF8 -/* --- UTF-7 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF7( - PyObject *unicode, /* Unicode object */ - int base64SetO, /* Encode RFC2152 Set O characters in base64 */ - int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ - const char *errors /* error handling */ - ); - -/* --- UTF-8 Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsUTF8String( - PyObject *unicode, - const char *errors); - -/* --- UTF-32 Codecs ------------------------------------------------------ */ - -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF32( - PyObject *object, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -/* --- UTF-16 Codecs ------------------------------------------------------ */ - -/* Returns a Python string object holding the UTF-16 encoded value of - the Unicode data. - - If byteorder is not 0, output is written according to the following - byte order: - - byteorder == -1: little endian - byteorder == 0: native byte order (writes a BOM mark) - byteorder == 1: big endian - - If byteorder is 0, the output string will always start with the - Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is - prepended. -*/ -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF16( - PyObject* unicode, /* Unicode object */ - const char *errors, /* error handling */ - int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ - ); - -/* --- Unicode-Escape Codecs ---------------------------------------------- */ - -/* Variant of PyUnicode_DecodeUnicodeEscape that supports partial decoding. */ -PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeStateful( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ -); -/* Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape - chars. */ -PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed, /* bytes consumed */ - const char **first_invalid_escape /* on return, points to first - invalid escaped char in - string. */ -); - -/* --- Raw-Unicode-Escape Codecs ---------------------------------------------- */ - -/* Variant of PyUnicode_DecodeRawUnicodeEscape that supports partial decoding. */ -PyAPI_FUNC(PyObject*) _PyUnicode_DecodeRawUnicodeEscapeStateful( - const char *string, /* Unicode-Escape encoded string */ - Py_ssize_t length, /* size of string */ - const char *errors, /* error handling */ - Py_ssize_t *consumed /* bytes consumed */ -); - -/* --- Latin-1 Codecs ----------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsLatin1String( - PyObject* unicode, - const char* errors); - -/* --- ASCII Codecs ------------------------------------------------------- */ - -PyAPI_FUNC(PyObject*) _PyUnicode_AsASCIIString( - PyObject* unicode, - const char* errors); - -/* --- Character Map Codecs ----------------------------------------------- */ - -/* Translate an Unicode object by applying a character mapping table to - it and return the resulting Unicode object. - - The mapping table must map Unicode ordinal integers to Unicode strings, - Unicode ordinal integers or None (causing deletion of the character). - - Mapping tables may be dictionaries or sequences. Unmapped character - ordinals (ones which cause a LookupError) are left untouched and - are copied as-is. -*/ -PyAPI_FUNC(PyObject*) _PyUnicode_EncodeCharmap( - PyObject *unicode, /* Unicode object */ - PyObject *mapping, /* encoding mapping */ - const char *errors /* error handling */ - ); - /* --- Decimal Encoder ---------------------------------------------------- */ /* Coverts a Unicode object holding a decimal value to an ASCII string diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index da01f57f962793..dd20ac19d413b8 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -177,6 +177,106 @@ PyAPI_FUNC(int) _PyUnicode_FormatAdvancedWriter( Py_ssize_t start, Py_ssize_t end); +/* --- UTF-7 Codecs ------------------------------------------------------- */ + +extern PyObject* _PyUnicode_EncodeUTF7( + PyObject *unicode, /* Unicode object */ + int base64SetO, /* Encode RFC2152 Set O characters in base64 */ + int base64WhiteSpace, /* Encode whitespace (sp, ht, nl, cr) in base64 */ + const char *errors); /* error handling */ + +/* --- UTF-8 Codecs ------------------------------------------------------- */ + +PyAPI_FUNC(PyObject*) _PyUnicode_AsUTF8String( + PyObject *unicode, + const char *errors); + +/* --- UTF-32 Codecs ------------------------------------------------------ */ + +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF32( + PyObject *object, /* Unicode object */ + const char *errors, /* error handling */ + int byteorder); /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + +/* --- UTF-16 Codecs ------------------------------------------------------ */ + +/* Returns a Python string object holding the UTF-16 encoded value of + the Unicode data. + + If byteorder is not 0, output is written according to the following + byte order: + + byteorder == -1: little endian + byteorder == 0: native byte order (writes a BOM mark) + byteorder == 1: big endian + + If byteorder is 0, the output string will always start with the + Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is + prepended. +*/ +PyAPI_FUNC(PyObject*) _PyUnicode_EncodeUTF16( + PyObject* unicode, /* Unicode object */ + const char *errors, /* error handling */ + int byteorder); /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + +/* --- Unicode-Escape Codecs ---------------------------------------------- */ + +/* Variant of PyUnicode_DecodeUnicodeEscape that supports partial decoding. */ +extern PyObject* _PyUnicode_DecodeUnicodeEscapeStateful( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed); /* bytes consumed */ + +/* Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape + chars. */ +PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed, /* bytes consumed */ + const char **first_invalid_escape); /* on return, points to first + invalid escaped char in + string. */ + +/* --- Raw-Unicode-Escape Codecs ---------------------------------------------- */ + +/* Variant of PyUnicode_DecodeRawUnicodeEscape that supports partial decoding. */ +extern PyObject* _PyUnicode_DecodeRawUnicodeEscapeStateful( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed); /* bytes consumed */ + +/* --- Latin-1 Codecs ----------------------------------------------------- */ + +extern PyObject* _PyUnicode_AsLatin1String( + PyObject* unicode, + const char* errors); + +/* --- ASCII Codecs ------------------------------------------------------- */ + +extern PyObject* _PyUnicode_AsASCIIString( + PyObject* unicode, + const char* errors); + +/* --- Character Map Codecs ----------------------------------------------- */ + +/* Translate an Unicode object by applying a character mapping table to + it and return the resulting Unicode object. + + The mapping table must map Unicode ordinal integers to Unicode strings, + Unicode ordinal integers or None (causing deletion of the character). + + Mapping tables may be dictionaries or sequences. Unmapped character + ordinals (ones which cause a LookupError) are left untouched and + are copied as-is. +*/ +extern PyObject* _PyUnicode_EncodeCharmap( + PyObject *unicode, /* Unicode object */ + PyObject *mapping, /* encoding mapping */ + const char *errors); /* error handling */ + /* --- Methods & Slots ---------------------------------------------------- */ extern PyObject* _PyUnicode_JoinArray( diff --git a/Parser/string_parser.c b/Parser/string_parser.c index 20459e89463494..bc1f99d607ae4d 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -1,6 +1,7 @@ #include #include +#include "pycore_unicodeobject.h" // _PyUnicode_DecodeUnicodeEscapeInternal() #include "tokenizer.h" #include "pegen.h" From ec931fc3943df0b94f2e250d7723892f2b3414bd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 10:27:23 +0200 Subject: [PATCH 257/446] gh-106320: Remove _PyBytesWriter C API (#106399) Remove the _PyBytesWriter C API: move it to the internal C API (pycore_bytesobject.h). --- Include/cpython/bytesobject.h | 80 -------------------------- Include/internal/pycore_bytesobject.h | 81 +++++++++++++++++++++++++++ Include/internal/pycore_long.h | 3 +- Modules/_pickle.c | 3 +- Modules/_struct.c | 1 + 5 files changed, 86 insertions(+), 82 deletions(-) diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h index e982031c107de2..0af4c83b1e5bc7 100644 --- a/Include/cpython/bytesobject.h +++ b/Include/cpython/bytesobject.h @@ -47,83 +47,3 @@ static inline Py_ssize_t PyBytes_GET_SIZE(PyObject *op) { /* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*, x must be an iterable object. */ PyAPI_FUNC(PyObject *) _PyBytes_Join(PyObject *sep, PyObject *x); - - -/* The _PyBytesWriter structure is big: it contains an embedded "stack buffer". - A _PyBytesWriter variable must be declared at the end of variables in a - function to optimize the memory allocation on the stack. */ -typedef struct { - /* bytes, bytearray or NULL (when the small buffer is used) */ - PyObject *buffer; - - /* Number of allocated size. */ - Py_ssize_t allocated; - - /* Minimum number of allocated bytes, - incremented by _PyBytesWriter_Prepare() */ - Py_ssize_t min_size; - - /* If non-zero, use a bytearray instead of a bytes object for buffer. */ - int use_bytearray; - - /* If non-zero, overallocate the buffer (default: 0). - This flag must be zero if use_bytearray is non-zero. */ - int overallocate; - - /* Stack buffer */ - int use_small_buffer; - char small_buffer[512]; -} _PyBytesWriter; - -/* Initialize a bytes writer - - By default, the overallocation is disabled. Set the overallocate attribute - to control the allocation of the buffer. */ -PyAPI_FUNC(void) _PyBytesWriter_Init(_PyBytesWriter *writer); - -/* Get the buffer content and reset the writer. - Return a bytes object, or a bytearray object if use_bytearray is non-zero. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject *) _PyBytesWriter_Finish(_PyBytesWriter *writer, - void *str); - -/* Deallocate memory of a writer (clear its internal buffer). */ -PyAPI_FUNC(void) _PyBytesWriter_Dealloc(_PyBytesWriter *writer); - -/* Allocate the buffer to write size bytes. - Return the pointer to the beginning of buffer data. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Alloc(_PyBytesWriter *writer, - Py_ssize_t size); - -/* Ensure that the buffer is large enough to write *size* bytes. - Add size to the writer minimum size (min_size attribute). - - str is the current pointer inside the buffer. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_Prepare(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Resize the buffer to make it larger. - The new buffer may be larger than size bytes because of overallocation. - Return the updated current pointer inside the buffer. - Raise an exception and return NULL on error. - - Note: size must be greater than the number of allocated bytes in the writer. - - This function doesn't use the writer minimum size (min_size attribute). - - See also _PyBytesWriter_Prepare(). - */ -PyAPI_FUNC(void*) _PyBytesWriter_Resize(_PyBytesWriter *writer, - void *str, - Py_ssize_t size); - -/* Write bytes. - Raise an exception and return NULL on error. */ -PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, - void *str, - const void *bytes, - Py_ssize_t size); diff --git a/Include/internal/pycore_bytesobject.h b/Include/internal/pycore_bytesobject.h index d36fa9569d64a5..115c0c52c8f9a9 100644 --- a/Include/internal/pycore_bytesobject.h +++ b/Include/internal/pycore_bytesobject.h @@ -41,6 +41,87 @@ PyAPI_FUNC(void) _PyBytes_Repeat(char* dest, Py_ssize_t len_dest, const char* src, Py_ssize_t len_src); +/* --- _PyBytesWriter ----------------------------------------------------- */ + +/* The _PyBytesWriter structure is big: it contains an embedded "stack buffer". + A _PyBytesWriter variable must be declared at the end of variables in a + function to optimize the memory allocation on the stack. */ +typedef struct { + /* bytes, bytearray or NULL (when the small buffer is used) */ + PyObject *buffer; + + /* Number of allocated size. */ + Py_ssize_t allocated; + + /* Minimum number of allocated bytes, + incremented by _PyBytesWriter_Prepare() */ + Py_ssize_t min_size; + + /* If non-zero, use a bytearray instead of a bytes object for buffer. */ + int use_bytearray; + + /* If non-zero, overallocate the buffer (default: 0). + This flag must be zero if use_bytearray is non-zero. */ + int overallocate; + + /* Stack buffer */ + int use_small_buffer; + char small_buffer[512]; +} _PyBytesWriter; + +/* Initialize a bytes writer + + By default, the overallocation is disabled. Set the overallocate attribute + to control the allocation of the buffer. */ +PyAPI_FUNC(void) _PyBytesWriter_Init(_PyBytesWriter *writer); + +/* Get the buffer content and reset the writer. + Return a bytes object, or a bytearray object if use_bytearray is non-zero. + Raise an exception and return NULL on error. */ +PyAPI_FUNC(PyObject *) _PyBytesWriter_Finish(_PyBytesWriter *writer, + void *str); + +/* Deallocate memory of a writer (clear its internal buffer). */ +PyAPI_FUNC(void) _PyBytesWriter_Dealloc(_PyBytesWriter *writer); + +/* Allocate the buffer to write size bytes. + Return the pointer to the beginning of buffer data. + Raise an exception and return NULL on error. */ +PyAPI_FUNC(void*) _PyBytesWriter_Alloc(_PyBytesWriter *writer, + Py_ssize_t size); + +/* Ensure that the buffer is large enough to write *size* bytes. + Add size to the writer minimum size (min_size attribute). + + str is the current pointer inside the buffer. + Return the updated current pointer inside the buffer. + Raise an exception and return NULL on error. */ +PyAPI_FUNC(void*) _PyBytesWriter_Prepare(_PyBytesWriter *writer, + void *str, + Py_ssize_t size); + +/* Resize the buffer to make it larger. + The new buffer may be larger than size bytes because of overallocation. + Return the updated current pointer inside the buffer. + Raise an exception and return NULL on error. + + Note: size must be greater than the number of allocated bytes in the writer. + + This function doesn't use the writer minimum size (min_size attribute). + + See also _PyBytesWriter_Prepare(). + */ +PyAPI_FUNC(void*) _PyBytesWriter_Resize(_PyBytesWriter *writer, + void *str, + Py_ssize_t size); + +/* Write bytes. + Raise an exception and return NULL on error. */ +PyAPI_FUNC(void*) _PyBytesWriter_WriteBytes(_PyBytesWriter *writer, + void *str, + const void *bytes, + Py_ssize_t size); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 64c00cb1475480..3f01694e5f5ac4 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -8,7 +8,8 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_global_objects.h" // _PY_NSMALLNEGINTS +#include "pycore_bytesobject.h" // _PyBytesWriter +#include "pycore_global_objects.h"// _PY_NSMALLNEGINTS #include "pycore_runtime.h" // _PyRuntime /* diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 4913a8dfee589e..a68a0aaa64c2b5 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -9,10 +9,11 @@ #endif #include "Python.h" +#include "pycore_bytesobject.h" // _PyBytesWriter #include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_moduleobject.h" // _PyModule_GetState() -#include "pycore_runtime.h" // _Py_ID() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_runtime.h" // _Py_ID() #include "structmember.h" // PyMemberDef #include // strtol() diff --git a/Modules/_struct.c b/Modules/_struct.c index 0a6f076aac0c53..31c94927e91d68 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -8,6 +8,7 @@ #endif #include "Python.h" +#include "pycore_bytesobject.h" // _PyBytesWriter #include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include From 8a73b57b9b5f6e36dd5a4c279f4d606d9e71a31f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 10:59:09 +0200 Subject: [PATCH 258/446] gh-106320: Remove _PyUnicode_TransformDecimalAndSpaceToASCII() (#106398) Remove private _PyUnicode_TransformDecimalAndSpaceToASCII() and other private _PyUnicode C API functions: move them to the internal C API (pycore_unicodeobject.h). No longer most of these functions. Replace _testcapi.unicode_transformdecimalandspacetoascii() with _testinternal._PyUnicode_TransformDecimalAndSpaceToASCII(). --- Include/cpython/unicodeobject.h | 37 ----------------------- Include/internal/pycore_unicodeobject.h | 39 +++++++++++++++++++++++-- Lib/test/test_capi/test_unicode.py | 8 +++-- Modules/_testcapi/unicode.c | 9 ------ Modules/_testinternalcapi.c | 12 ++++++++ Python/pystrhex.c | 1 + 6 files changed, 56 insertions(+), 50 deletions(-) diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index dc8f6437c0e2c4..e75b5e154943dc 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -167,10 +167,6 @@ typedef struct { } data; /* Canonical, smallest-form Unicode buffer */ } PyUnicodeObject; -PyAPI_FUNC(int) _PyUnicode_CheckConsistency( - PyObject *op, - int check_content); - #define _PyASCIIObject_CAST(op) \ (assert(PyUnicode_Check(op)), \ @@ -461,19 +457,6 @@ PyAPI_FUNC(const char *) PyUnicode_AsUTF8(PyObject *unicode); #define _PyUnicode_AsString PyUnicode_AsUTF8 -/* --- Decimal Encoder ---------------------------------------------------- */ - -/* Coverts a Unicode object holding a decimal value to an ASCII string - for using in int, float and complex parsers. - Transforms code points that have decimal digit property to the - corresponding ASCII digit code points. Transforms spaces to ASCII. - Transforms code points starting from the first non-ASCII code point that - is neither a decimal digit nor a space to the end into '?'. */ - -PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( - PyObject *unicode /* Unicode object */ - ); - /* === Characters Type APIs =============================================== */ /* These should not be used directly. Use the Py_UNICODE_IS* and @@ -623,23 +606,3 @@ static inline int Py_UNICODE_ISALNUM(Py_UCS4 ch) { || Py_UNICODE_ISDIGIT(ch) || Py_UNICODE_ISNUMERIC(ch)); } - - -/* === Misc functions ===================================================== */ - -PyAPI_FUNC(PyObject*) _PyUnicode_FormatLong(PyObject *, int, int, int); - -/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/ -PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); - -/* Fast equality check when the inputs are known to be exact unicode types - and where the hash values are equal (i.e. a very probable match) */ -PyAPI_FUNC(int) _PyUnicode_EQ(PyObject *, PyObject *); - -/* Equality check. */ -PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *, PyObject *); - -PyAPI_FUNC(int) _PyUnicode_WideCharString_Converter(PyObject *, void *); -PyAPI_FUNC(int) _PyUnicode_WideCharString_Opt_Converter(PyObject *, void *); - -PyAPI_FUNC(Py_ssize_t) _PyUnicode_ScanIdentifier(PyObject *); diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index dd20ac19d413b8..ad59c3e385f2d3 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -11,8 +11,12 @@ extern "C" { #include "pycore_fileutils.h" // _Py_error_handler #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI -void _PyUnicode_ExactDealloc(PyObject *op); -Py_ssize_t _PyUnicode_InternedSize(void); +PyAPI_FUNC(int) _PyUnicode_CheckConsistency( + PyObject *op, + int check_content); + +extern void _PyUnicode_ExactDealloc(PyObject *op); +extern Py_ssize_t _PyUnicode_InternedSize(void); /* Get a copy of a Unicode string. */ PyAPI_FUNC(PyObject*) _PyUnicode_Copy( @@ -277,6 +281,18 @@ extern PyObject* _PyUnicode_EncodeCharmap( PyObject *mapping, /* encoding mapping */ const char *errors); /* error handling */ +/* --- Decimal Encoder ---------------------------------------------------- */ + +/* Coverts a Unicode object holding a decimal value to an ASCII string + for using in int, float and complex parsers. + Transforms code points that have decimal digit property to the + corresponding ASCII digit code points. Transforms spaces to ASCII. + Transforms code points starting from the first non-ASCII code point that + is neither a decimal digit nor a space to the end into '?'. */ + +PyAPI_FUNC(PyObject*) _PyUnicode_TransformDecimalAndSpaceToASCII( + PyObject *unicode); /* Unicode object */ + /* --- Methods & Slots ---------------------------------------------------- */ extern PyObject* _PyUnicode_JoinArray( @@ -323,6 +339,25 @@ extern Py_ssize_t _PyUnicode_InsertThousandsGrouping( PyObject *thousands_sep, Py_UCS4 *maxchar); +/* --- Misc functions ----------------------------------------------------- */ + +extern PyObject* _PyUnicode_FormatLong(PyObject *, int, int, int); + +/* Return an interned Unicode object for an Identifier; may fail if there is no memory.*/ +PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*); + +/* Fast equality check when the inputs are known to be exact unicode types + and where the hash values are equal (i.e. a very probable match) */ +extern int _PyUnicode_EQ(PyObject *, PyObject *); + +/* Equality check. */ +PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *, PyObject *); + +extern int _PyUnicode_WideCharString_Converter(PyObject *, void *); +extern int _PyUnicode_WideCharString_Opt_Converter(PyObject *, void *); + +PyAPI_FUNC(Py_ssize_t) _PyUnicode_ScanIdentifier(PyObject *); + /* --- Runtime lifecycle -------------------------------------------------- */ extern void _PyUnicode_InitState(PyInterpreterState *); diff --git a/Lib/test/test_capi/test_unicode.py b/Lib/test/test_capi/test_unicode.py index ca914459a62bec..622ee8993907fa 100644 --- a/Lib/test/test_capi/test_unicode.py +++ b/Lib/test/test_capi/test_unicode.py @@ -7,6 +7,10 @@ import _testcapi except ImportError: _testcapi = None +try: + import _testinternalcapi +except ImportError: + _testinternalcapi = None NULL = None @@ -913,10 +917,10 @@ def test_getdefaultencoding(self): self.assertEqual(getdefaultencoding(), b'utf-8') @support.cpython_only - @unittest.skipIf(_testcapi is None, 'need _testcapi module') + @unittest.skipIf(_testinternalcapi is None, 'need _testinternalcapi module') def test_transform_decimal_and_space(self): """Test _PyUnicode_TransformDecimalAndSpaceToASCII()""" - from _testcapi import unicode_transformdecimalandspacetoascii as transform_decimal + from _testinternalcapi import _PyUnicode_TransformDecimalAndSpaceToASCII as transform_decimal self.assertEqual(transform_decimal('123'), '123') diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 9c2760c3f763a6..51d741a6b5ff1c 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -660,14 +660,6 @@ unicode_getdefaultencoding(PyObject *self, PyObject *Py_UNUSED(ignored)) return PyBytes_FromString(s); } -/* Test _PyUnicode_TransformDecimalAndSpaceToASCII() */ -static PyObject * -unicode_transformdecimalandspacetoascii(PyObject *self, PyObject *arg) -{ - NULLABLE(arg); - return _PyUnicode_TransformDecimalAndSpaceToASCII(arg); -} - /* Test PyUnicode_DecodeUTF8() */ static PyObject * unicode_decodeutf8(PyObject *self, PyObject *args) @@ -1544,7 +1536,6 @@ static PyMethodDef TestMethods[] = { {"unicode_decodeutf8", unicode_decodeutf8, METH_VARARGS}, {"unicode_decodeutf8stateful",unicode_decodeutf8stateful, METH_VARARGS}, {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, - {"unicode_transformdecimalandspacetoascii", unicode_transformdecimalandspacetoascii, METH_O}, {"unicode_concat", unicode_concat, METH_VARARGS}, {"unicode_splitlines", unicode_splitlines, METH_VARARGS}, {"unicode_split", unicode_split, METH_VARARGS}, diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 4875ee7bed1683..14f91e8da1716a 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1253,6 +1253,17 @@ test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) } +/* Test _PyUnicode_TransformDecimalAndSpaceToASCII() */ +static PyObject * +unicode_transformdecimalandspacetoascii(PyObject *self, PyObject *arg) +{ + if (arg == Py_None) { + arg = NULL; + } + return _PyUnicode_TransformDecimalAndSpaceToASCII(arg); +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1304,6 +1315,7 @@ static PyMethodDef module_functions[] = { {"_PyTime_ObjectToTimeval", test_pytime_object_to_timeval, METH_VARARGS}, {"_PyTraceMalloc_GetTraceback", tracemalloc_get_traceback, METH_VARARGS}, {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, + {"_PyUnicode_TransformDecimalAndSpaceToASCII", unicode_transformdecimalandspacetoascii, METH_O}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/pystrhex.c b/Python/pystrhex.c index f798256e18ebdb..ce456b79f1655f 100644 --- a/Python/pystrhex.c +++ b/Python/pystrhex.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_strhex.h" // _Py_strhex_with_sep() +#include "pycore_unicodeobject.h" // _PyUnicode_CheckConsistency() #include // abs() static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, From c9ce983ae1a361f431a0303aeb6f4b8e1d674275 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 11:41:43 +0200 Subject: [PATCH 259/446] gh-106320: Remove private pylifecycle.h functions (#106400) Remove private pylifecycle.h functions: move them to the internal C API ( pycore_atexit.h, pycore_pylifecycle.h and pycore_signal.h). No longer export most of these functions. Move _testcapi.test_atexit() to _testinternalcapi. --- Include/cpython/pylifecycle.h | 27 ++---------------- Include/internal/pycore_atexit.h | 7 ++++- Include/internal/pycore_pylifecycle.h | 41 ++++++++++++++++++++------- Include/internal/pycore_signal.h | 4 ++- Modules/_asynciomodule.c | 3 +- Modules/_io/bufferedio.c | 1 + Modules/_posixsubprocess.c | 4 ++- Modules/_randommodule.c | 1 + Modules/_sqlite/connection.c | 1 + Modules/_testcapimodule.c | 32 --------------------- Modules/_testinternalcapi.c | 33 +++++++++++++++++++++ Modules/_xxinterpchannelsmodule.c | 6 +++- Modules/getbuildinfo.c | 5 ++++ Modules/posixmodule.c | 1 + Modules/readline.c | 5 ++++ Modules/signalmodule.c | 2 +- Python/_warnings.c | 3 +- Python/bootstrap_hash.c | 3 +- Python/preconfig.c | 1 + 19 files changed, 104 insertions(+), 76 deletions(-) diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index 1ca9ee91a72b15..8af34b05642512 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -19,13 +19,13 @@ PyAPI_FUNC(PyStatus) Py_PreInitializeFromArgs( Py_ssize_t argc, wchar_t **argv); -PyAPI_FUNC(int) _Py_IsCoreInitialized(void); - /* Initialization and finalization */ PyAPI_FUNC(PyStatus) Py_InitializeFromConfig( const PyConfig *config); + +// Python 3.8 provisional API (PEP 587) PyAPI_FUNC(PyStatus) _Py_InitializeMain(void); PyAPI_FUNC(int) Py_RunMain(void); @@ -33,31 +33,8 @@ PyAPI_FUNC(int) Py_RunMain(void); PyAPI_FUNC(void) _Py_NO_RETURN Py_ExitStatusException(PyStatus err); -/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ -PyAPI_FUNC(void) _Py_RestoreSignals(void); - PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); -PyAPI_FUNC(int) _Py_FdIsInteractive(FILE *fp, PyObject *filename); - -PyAPI_FUNC(const char *) _Py_gitidentifier(void); -PyAPI_FUNC(const char *) _Py_gitversion(void); - -PyAPI_FUNC(int) _Py_IsFinalizing(void); -PyAPI_FUNC(int) _Py_IsInterpreterFinalizing(PyInterpreterState *interp); - -/* Random */ -PyAPI_FUNC(int) _PyOS_URandom(void *buffer, Py_ssize_t size); -PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size); - -/* Legacy locale support */ -PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); -PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); -PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); PyAPI_FUNC(PyStatus) Py_NewInterpreterFromConfig( PyThreadState **tstate_p, const PyInterpreterConfig *config); - -typedef void (*atexit_datacallbackfunc)(void *); -PyAPI_FUNC(int) _Py_AtExit( - PyInterpreterState *, atexit_datacallbackfunc, void *); diff --git a/Include/internal/pycore_atexit.h b/Include/internal/pycore_atexit.h index 63a2cd5d507d2c..fc5cb6d8826435 100644 --- a/Include/internal/pycore_atexit.h +++ b/Include/internal/pycore_atexit.h @@ -25,7 +25,8 @@ struct _atexit_runtime_state { //################### // interpreter atexit -struct atexit_callback; +typedef void (*atexit_datacallbackfunc)(void *); + typedef struct atexit_callback { atexit_datacallbackfunc func; void *data; @@ -50,6 +51,10 @@ struct atexit_state { int callback_len; }; +PyAPI_FUNC(int) _Py_AtExit( + PyInterpreterState *interp, + atexit_datacallbackfunc func, + void *data); #ifdef __cplusplus } diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index b07c2dba8de847..fb28652515909d 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -23,7 +23,7 @@ extern PyStatus _PyUnicode_InitEncodings(PyThreadState *tstate); extern int _PyUnicode_EnableLegacyWindowsFSEncoding(void); #endif -PyAPI_FUNC(int) _Py_IsLocaleCoercionTarget(const char *ctype_loc); +extern int _Py_IsLocaleCoercionTarget(const char *ctype_loc); /* Various one-time initializers */ @@ -67,30 +67,49 @@ extern PyStatus _PyGILState_Init(PyInterpreterState *interp); extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate); extern void _PyGILState_Fini(PyInterpreterState *interp); -PyAPI_FUNC(void) _PyGC_DumpShutdownStats(PyInterpreterState *interp); +extern void _PyGC_DumpShutdownStats(PyInterpreterState *interp); -PyAPI_FUNC(PyStatus) _Py_PreInitializeFromPyArgv( +extern PyStatus _Py_PreInitializeFromPyArgv( const PyPreConfig *src_config, const struct _PyArgv *args); -PyAPI_FUNC(PyStatus) _Py_PreInitializeFromConfig( +extern PyStatus _Py_PreInitializeFromConfig( const PyConfig *config, const struct _PyArgv *args); -PyAPI_FUNC(wchar_t *) _Py_GetStdlibDir(void); +extern wchar_t * _Py_GetStdlibDir(void); -PyAPI_FUNC(int) _Py_HandleSystemExit(int *exitcode_p); +extern int _Py_HandleSystemExit(int *exitcode_p); -PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); +extern PyObject* _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); -PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); -PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, +extern void _PyErr_Print(PyThreadState *tstate); +extern void _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb); -PyAPI_FUNC(void) _PyErr_DisplayException(PyObject *file, PyObject *exc); +extern void _PyErr_DisplayException(PyObject *file, PyObject *exc); -PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate); +extern void _PyThreadState_DeleteCurrent(PyThreadState *tstate); extern void _PyAtExit_Call(PyInterpreterState *interp); +extern int _Py_IsCoreInitialized(void); + +extern int _Py_FdIsInteractive(FILE *fp, PyObject *filename); + +extern const char* _Py_gitidentifier(void); +extern const char* _Py_gitversion(void); + +extern int _Py_IsFinalizing(void); +PyAPI_FUNC(int) _Py_IsInterpreterFinalizing(PyInterpreterState *interp); + +/* Random */ +extern int _PyOS_URandom(void *buffer, Py_ssize_t size); +PyAPI_FUNC(int) _PyOS_URandomNonblock(void *buffer, Py_ssize_t size); + +/* Legacy locale support */ +extern int _Py_CoerceLegacyLocale(int warn); +extern int _Py_LegacyLocaleDetected(int warn); +PyAPI_FUNC(char*) _Py_SetLocaleFromEnv(int category); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_signal.h b/Include/internal/pycore_signal.h index ca3f69d09fc0c1..1a454ba6f4e8fb 100644 --- a/Include/internal/pycore_signal.h +++ b/Include/internal/pycore_signal.h @@ -11,10 +11,12 @@ extern "C" { #endif #include "pycore_atomic.h" // _Py_atomic_address - #include // NSIG +/* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */ +PyAPI_FUNC(void) _Py_RestoreSignals(void); + #ifdef _SIG_MAXSIG // gh-91145: On FreeBSD, defines NSIG as 32: it doesn't include // realtime signals: [SIGRTMIN,SIGRTMAX]. Use _SIG_MAXSIG instead. For diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 05f94ef9ed2816..3843f9c45d7236 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -3,10 +3,11 @@ #endif #include "Python.h" +#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pyerrors.h" // _PyErr_ClearExcState() +#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_runtime_init.h" // _Py_ID() -#include "pycore_moduleobject.h" // _PyModule_GetState() #include "structmember.h" // PyMemberDef #include // offsetof() diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 4d120d4e8af3a7..e58e87926f6731 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -11,6 +11,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_object.h" #include "pycore_pyerrors.h" // _Py_FatalErrorFormat() +#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "structmember.h" // PyMemberDef #include "_iomodule.h" diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 6caa4b8852911e..ac2b0d4f55468c 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -6,6 +6,7 @@ #include "Python.h" #include "pycore_fileutils.h" #include "pycore_pystate.h" +#include "pycore_signal.h" // _Py_RestoreSignals() #if defined(HAVE_PIPE2) && !defined(_GNU_SOURCE) # define _GNU_SOURCE #endif @@ -739,8 +740,9 @@ child_exec(char *const exec_array[], if (child_umask >= 0) umask(child_umask); /* umask() always succeeds. */ - if (restore_signals) + if (restore_signals) { _Py_RestoreSignals(); + } #ifdef VFORK_USABLE if (child_sigmask) { diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index fda5ef267fb470..7daa1f9327966f 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -72,6 +72,7 @@ #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include "pycore_runtime.h" #ifdef HAVE_PROCESS_H # include // getpid() diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index d71cef14779e51..bab743674b666d 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -34,6 +34,7 @@ #include "prepare_protocol.h" #include "util.h" #include "pycore_import.h" // _PyImport_GetModuleAttrString() +#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_weakref.h" // _PyWeakref_IS_DEAD() #include diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index d1044b5445202d..2baf453f710267 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3293,37 +3293,6 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } -struct atexit_data { - int called; -}; - -static void -callback(void *data) -{ - ((struct atexit_data *)data)->called += 1; -} - -static PyObject * -test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) -{ - PyThreadState *oldts = PyThreadState_Swap(NULL); - PyThreadState *tstate = Py_NewInterpreter(); - - struct atexit_data data = {0}; - int res = _Py_AtExit(tstate->interp, callback, (void *)&data); - Py_EndInterpreter(tstate); - PyThreadState_Swap(oldts); - if (res < 0) { - return NULL; - } - if (data.called == 0) { - PyErr_SetString(PyExc_RuntimeError, "atexit callback not called"); - return NULL; - } - Py_RETURN_NONE; -} - - static PyObject * check_pyimport_addmodule(PyObject *self, PyObject *args) { @@ -3613,7 +3582,6 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, - {"test_atexit", test_atexit, METH_NOARGS}, {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS}, {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, {NULL, NULL} /* sentinel */ diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 14f91e8da1716a..84511d27e37f45 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1264,6 +1264,38 @@ unicode_transformdecimalandspacetoascii(PyObject *self, PyObject *arg) } +struct atexit_data { + int called; +}; + +static void +callback(void *data) +{ + ((struct atexit_data *)data)->called += 1; +} + +static PyObject * +test_atexit(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyThreadState *oldts = PyThreadState_Swap(NULL); + PyThreadState *tstate = Py_NewInterpreter(); + + struct atexit_data data = {0}; + int res = _Py_AtExit(tstate->interp, callback, (void *)&data); + Py_EndInterpreter(tstate); + PyThreadState_Swap(oldts); + if (res < 0) { + return NULL; + } + + if (data.called == 0) { + PyErr_SetString(PyExc_RuntimeError, "atexit callback not called"); + return NULL; + } + Py_RETURN_NONE; +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1316,6 +1348,7 @@ static PyMethodDef module_functions[] = { {"_PyTraceMalloc_GetTraceback", tracemalloc_get_traceback, METH_VARARGS}, {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL}, {"_PyUnicode_TransformDecimalAndSpaceToASCII", unicode_transformdecimalandspacetoascii, METH_O}, + {"test_atexit", test_atexit, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index 1d7e7f1d71af3e..82472555ec7d62 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -1,9 +1,13 @@ - /* interpreters module */ /* low-level access to interpreter primitives */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" #include "interpreteridobject.h" +#include "pycore_atexit.h" // _Py_AtExit() /* diff --git a/Modules/getbuildinfo.c b/Modules/getbuildinfo.c index a24750b76c09bc..8d553d106c6ab5 100644 --- a/Modules/getbuildinfo.c +++ b/Modules/getbuildinfo.c @@ -1,4 +1,9 @@ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" +#include "pycore_pylifecycle.h" // _Py_gitidentifier() #ifndef DONT_HAVE_STDIO_H #include diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b9f42476e6b82c..aef802c232c6ce 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -19,6 +19,7 @@ #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_object.h" // _PyObject_LookupSpecial() +#include "pycore_pylifecycle.h" // _PyOS_URandom() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_signal.h" // Py_NSIG diff --git a/Modules/readline.c b/Modules/readline.c index ff7075c6822e27..a592919692cb83 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -4,8 +4,13 @@ * recently, it was largely rewritten by Guido van Rossum. */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + /* Standard definitions */ #include "Python.h" +#include "pycore_pylifecycle.h" // _Py_SetLocaleFromEnv() #include #include diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 00ea4343735dab..3adb2e8dfe58d8 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -13,7 +13,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_signal.h" // Py_NSIG +#include "pycore_signal.h" // _Py_RestoreSignals() #ifndef MS_WINDOWS # include "posixmodule.h" diff --git a/Python/_warnings.c b/Python/_warnings.c index e4941f7b068d3f..e0580f01d9361d 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1,10 +1,11 @@ #include "Python.h" +#include "pycore_frame.h" #include "pycore_initconfig.h" #include "pycore_interp.h" // PyInterpreterState.warnings #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_pyerrors.h" +#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_frame.h" #include "clinic/_warnings.c.h" #define MODULE_NAME "_warnings" diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c index 587063ef1ab29a..ef693e5df1fcc4 100644 --- a/Python/bootstrap_hash.c +++ b/Python/bootstrap_hash.c @@ -1,6 +1,7 @@ #include "Python.h" -#include "pycore_initconfig.h" #include "pycore_fileutils.h" // _Py_fstat_noraise() +#include "pycore_initconfig.h" +#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include "pycore_runtime.h" // _PyRuntime #ifdef MS_WINDOWS diff --git a/Python/preconfig.c b/Python/preconfig.c index 77a86d651eb0f4..5b26c75de8b3a0 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -2,6 +2,7 @@ #include "pycore_fileutils.h" // DECODE_LOCALE_ERR #include "pycore_getopt.h" // _PyOS_GetOpt() #include "pycore_initconfig.h" // _PyArgv +#include "pycore_pylifecycle.h" // _Py_LegacyLocaleDetected() #include "pycore_pymem.h" // _PyMem_GetAllocatorName() #include "pycore_runtime.h" // _PyRuntime_Initialize() From e4ba71fe4b32ae0d7fb3319d697616470fba1e58 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 4 Jul 2023 03:03:57 -0700 Subject: [PATCH 260/446] GH-106008: Fix refleak when peepholing `None` comparisons (#106367) --- .../2023-07-03-11-38-43.gh-issue-106008.HDf1zd.rst | 2 ++ Python/flowgraph.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-03-11-38-43.gh-issue-106008.HDf1zd.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-03-11-38-43.gh-issue-106008.HDf1zd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-03-11-38-43.gh-issue-106008.HDf1zd.rst new file mode 100644 index 00000000000000..a57b892fd53242 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-03-11-38-43.gh-issue-106008.HDf1zd.rst @@ -0,0 +1,2 @@ +Fix possible reference leaks when failing to optimize comparisons with +:const:`None` in the bytecode compiler. diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 213c993bb863a3..e159a4356dfe46 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1377,9 +1377,9 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) goto error; } if (!Py_IsNone(cnt)) { + Py_DECREF(cnt); break; } - Py_DECREF(cnt); if (bb->b_iused <= i + 2) { break; } From 8f6df5e9cbc3a1689601714192aa6ecbb23e1927 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 4 Jul 2023 13:36:40 +0200 Subject: [PATCH 261/446] gh-106368: Add tests for permutation helpers in Argument Clinic (#106407) Added new test class PermutationTests() --- Lib/test/test_clinic.py | 106 ++++++++++++++++++++++++++++++++++++++++ Tools/clinic/clinic.py | 4 +- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 03754d0bf123be..544e7323e4f606 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1586,5 +1586,111 @@ def test_cloned_func_with_converter_exception_message(self): self.assertEqual(func(), name) +class PermutationTests(unittest.TestCase): + """Test permutation support functions.""" + + def test_permute_left_option_groups(self): + expected = ( + (), + (3,), + (2, 3), + (1, 2, 3), + ) + data = list(zip([1, 2, 3])) # Generate a list of 1-tuples. + actual = tuple(clinic.permute_left_option_groups(data)) + self.assertEqual(actual, expected) + + def test_permute_right_option_groups(self): + expected = ( + (), + (1,), + (1, 2), + (1, 2, 3), + ) + data = list(zip([1, 2, 3])) # Generate a list of 1-tuples. + actual = tuple(clinic.permute_right_option_groups(data)) + self.assertEqual(actual, expected) + + def test_permute_optional_groups(self): + empty = { + "left": (), "required": (), "right": (), + "expected": ((),), + } + noleft1 = { + "left": (), "required": ("b",), "right": ("c",), + "expected": ( + ("b",), + ("b", "c"), + ), + } + noleft2 = { + "left": (), "required": ("b", "c",), "right": ("d",), + "expected": ( + ("b", "c"), + ("b", "c", "d"), + ), + } + noleft3 = { + "left": (), "required": ("b", "c",), "right": ("d", "e"), + "expected": ( + ("b", "c"), + ("b", "c", "d"), + ("b", "c", "d", "e"), + ), + } + noright1 = { + "left": ("a",), "required": ("b",), "right": (), + "expected": ( + ("b",), + ("a", "b"), + ), + } + noright2 = { + "left": ("a",), "required": ("b", "c"), "right": (), + "expected": ( + ("b", "c"), + ("a", "b", "c"), + ), + } + noright3 = { + "left": ("a", "b"), "required": ("c",), "right": (), + "expected": ( + ("c",), + ("b", "c"), + ("a", "b", "c"), + ), + } + leftandright1 = { + "left": ("a",), "required": ("b",), "right": ("c",), + "expected": ( + ("b",), + ("a", "b"), # Prefer left. + ("a", "b", "c"), + ), + } + leftandright2 = { + "left": ("a", "b"), "required": ("c", "d"), "right": ("e", "f"), + "expected": ( + ("c", "d"), + ("b", "c", "d"), # Prefer left. + ("a", "b", "c", "d"), # Prefer left. + ("a", "b", "c", "d", "e"), + ("a", "b", "c", "d", "e", "f"), + ), + } + dataset = ( + empty, + noleft1, noleft2, noleft3, + noright1, noright2, noright3, + leftandright1, leftandright2, + ) + for params in dataset: + with self.subTest(**params): + left, required, right, expected = params.values() + permutations = clinic.permute_optional_groups(left, required, right) + actual = tuple(permutations) + self.assertEqual(actual, expected) + + if __name__ == "__main__": unittest.main() diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index a07fcbd8cabf76..c02c82876591f8 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -518,7 +518,7 @@ class PythonLanguage(Language): def permute_left_option_groups(l): """ - Given [1, 2, 3], should yield: + Given [(1,), (2,), (3,)], should yield: () (3,) (2, 3) @@ -533,7 +533,7 @@ def permute_left_option_groups(l): def permute_right_option_groups(l): """ - Given [1, 2, 3], should yield: + Given [(1,), (2,), (3,)], should yield: () (1,) (1, 2) From dfe4de203881e8d068e6fc5b8e31075841a86d25 Mon Sep 17 00:00:00 2001 From: Lysandros Nikolaou Date: Tue, 4 Jul 2023 14:19:08 +0200 Subject: [PATCH 262/446] gh-106396: Special-case empty format spec to gen empty JoinedStr node (#106401) --- Lib/test/test_fstring.py | 18 ++++++++++++++++++ ...3-07-04-09-51-45.gh-issue-106396.DmYp7x.rst | 3 +++ Parser/action_helpers.c | 12 ++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index ba223ae124a8fb..cb14bba2602def 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -496,6 +496,24 @@ def test_ast_line_numbers_with_parentheses(self): self.assertEqual(wat2.end_col_offset, 17) self.assertEqual(fstring.end_col_offset, 18) + def test_ast_fstring_empty_format_spec(self): + expr = "f'{expr:}'" + + mod = ast.parse(expr) + self.assertEqual(type(mod), ast.Module) + self.assertEqual(len(mod.body), 1) + + fstring = mod.body[0].value + self.assertEqual(type(fstring), ast.JoinedStr) + self.assertEqual(len(fstring.values), 1) + + fv = fstring.values[0] + self.assertEqual(type(fv), ast.FormattedValue) + + format_spec = fv.format_spec + self.assertEqual(type(format_spec), ast.JoinedStr) + self.assertEqual(len(format_spec.values), 0) + def test_docstring(self): def f(): f'''Not a docstring''' diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst new file mode 100644 index 00000000000000..c5767e97271d9d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-09-51-45.gh-issue-106396.DmYp7x.rst @@ -0,0 +1,3 @@ +When the format specification of an f-string expression is empty, the parser now +generates an empty :class:`ast.JoinedStr` node for it instead of an one-element +:class:`ast.JoinedStr` with an empty string :class:`ast.Constant`. diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c index 70c267bb212fcb..36e0750220a30d 100644 --- a/Parser/action_helpers.c +++ b/Parser/action_helpers.c @@ -997,6 +997,18 @@ _PyPegen_setup_full_format_spec(Parser *p, Token *colon, asdl_expr_seq *spec, in if (!spec) { return NULL; } + + // This is needed to keep compatibility with 3.11, where an empty format spec is parsed + // as an *empty* JoinedStr node, instead of having an empty constant in it. + if (asdl_seq_LEN(spec) == 1) { + expr_ty e = asdl_seq_GET(spec, 0); + if (e->kind == Constant_kind + && PyUnicode_Check(e->v.Constant.value) + && PyUnicode_GetLength(e->v.Constant.value) == 0) { + spec = _Py_asdl_expr_seq_new(0, arena); + } + } + expr_ty res = _PyAST_JoinedStr(spec, lineno, col_offset, end_lineno, end_col_offset, p->arena); if (!res) { return NULL; From 80f1c6c49b4cd2bf698eb2bc3d2f3da904880dd2 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 4 Jul 2023 17:19:20 +0300 Subject: [PATCH 263/446] gh-106406: Fix _Py_IsInterpreterFinalizing() in _winapi.c (#106408) --- Modules/_winapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_winapi.c b/Modules/_winapi.c index d4291f557b6a66..313c12a34c6725 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -36,6 +36,7 @@ #include "Python.h" #include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_pystate.h" // _PyInterpreterState_GET #include "structmember.h" // PyMemberDef From 318ea2c72e9aed7ac92457c28747eda9424c8327 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 4 Jul 2023 17:23:00 +0100 Subject: [PATCH 264/446] GH-106360: Support very basic superblock introspection (#106422) * Add len() and indexing support to uop superblocks. --- Include/cpython/optimizer.h | 2 + Include/internal/pycore_opcode.h | 9 ++-- Lib/test/test_capi/test_misc.py | 23 ++++++++ Modules/_testinternalcapi.c | 21 ++++++++ Python/opcode_metadata.h | 6 +-- Python/optimizer.c | 70 +++++++++++++++++++++++++ Tools/build/generate_opcode_h.py | 7 +-- Tools/cases_generator/generate_cases.py | 6 +-- 8 files changed, 130 insertions(+), 14 deletions(-) diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h index 2664f5bc4b1742..2260501bfd608e 100644 --- a/Include/cpython/optimizer.h +++ b/Include/cpython/optimizer.h @@ -38,6 +38,8 @@ PyAPI_FUNC(void) PyUnstable_SetOptimizer(_PyOptimizerObject* optimizer); PyAPI_FUNC(_PyOptimizerObject *) PyUnstable_GetOptimizer(void); +PyAPI_FUNC(_PyExecutorObject *)PyUnstable_GetExecutor(PyCodeObject *code, int offset); + struct _PyInterpreterFrame * _PyOptimizer_BackEdge(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 428df4ccadbc19..c7c2fdcc327884 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -242,8 +242,11 @@ const uint8_t _PyOpcode_Deopt[256] = { }; #endif // NEED_OPCODE_TABLES -#ifdef Py_DEBUG -static const char *const _PyOpcode_OpName[268] = { + +extern const char *const _PyOpcode_OpName[268]; + +#ifdef NEED_OPCODE_TABLES +const char *const _PyOpcode_OpName[268] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", [PUSH_NULL] = "PUSH_NULL", @@ -513,7 +516,7 @@ static const char *const _PyOpcode_OpName[268] = { [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL", [LOAD_CLOSURE] = "LOAD_CLOSURE", }; -#endif +#endif // NEED_OPCODE_TABLES #define EXTRA_CASES \ case 184: \ diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9e825a343eb318..de9f00a9e5fb48 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2415,5 +2415,28 @@ def long_loop(): self.assertEqual(opt.get_count(), 10) +class TestUops(unittest.TestCase): + + def test_basic_loop(self): + + def testfunc(x): + i = 0 + while i < x: + i += 1 + + testfunc(1000) + + ex = None + for offset in range(0, 100, 2): + try: + ex = _testinternalcapi.get_executor(testfunc.__code__, offset) + break + except ValueError: + pass + if ex is None: + return + self.assertIn("SAVE_IP", str(ex)) + + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 84511d27e37f45..52e524a40672ed 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -858,6 +858,26 @@ get_optimizer(PyObject *self, PyObject *Py_UNUSED(ignored)) return opt; } +static PyObject * +get_executor(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + + if (!_PyArg_CheckPositional("get_executor", nargs, 2, 2)) { + return NULL; + } + PyObject *code = args[0]; + PyObject *offset = args[1]; + long ioffset = PyLong_AsLong(offset); + if (ioffset == -1 && PyErr_Occurred()) { + return NULL; + } + if (!PyCode_Check(code)) { + PyErr_SetString(PyExc_TypeError, "first argument must be a code object"); + return NULL; + } + return (PyObject *)PyUnstable_GetExecutor((PyCodeObject *)code, ioffset); +} + static int _pending_callback(void *arg) { /* we assume the argument is callable object to which we own a reference */ @@ -1326,6 +1346,7 @@ static PyMethodDef module_functions[] = { {"iframe_getlasti", iframe_getlasti, METH_O, NULL}, {"get_optimizer", get_optimizer, METH_NOARGS, NULL}, {"set_optimizer", set_optimizer, METH_O, NULL}, + {"get_executor", _PyCFunction_CAST(get_executor), METH_FASTCALL, NULL}, {"get_counter_optimizer", get_counter_optimizer, METH_NOARGS, NULL}, {"get_uop_optimizer", get_uop_optimizer, METH_NOARGS, NULL}, {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 82c98235892287..ac86a4abd9c1b3 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -942,9 +942,7 @@ struct opcode_macro_expansion { #ifndef NEED_OPCODE_METADATA extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; -#ifdef Py_DEBUG extern const char * const _PyOpcode_uop_name[512]; -#endif #else const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [NOP] = { true, INSTR_FMT_IX, 0 }, @@ -1265,7 +1263,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; -#ifdef Py_DEBUG +#ifdef NEED_OPCODE_METADATA const char * const _PyOpcode_uop_name[512] = { [300] = "EXIT_TRACE", [301] = "SAVE_IP", @@ -1282,5 +1280,5 @@ const char * const _PyOpcode_uop_name[512] = { [312] = "_LOAD_LOCALS", [313] = "_LOAD_FROM_DICT_OR_GLOBALS", }; -#endif +#endif // NEED_OPCODE_METADATA #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 32f0b1477d203c..c3ab649b51b0eb 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -188,6 +188,23 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI return frame; } +_PyExecutorObject * +PyUnstable_GetExecutor(PyCodeObject *code, int offset) +{ + int code_len = (int)Py_SIZE(code); + for (int i = 0 ; i < code_len;) { + if (_PyCode_CODE(code)[i].op.code == ENTER_EXECUTOR && i*2 == offset) { + int oparg = _PyCode_CODE(code)[i].op.arg; + _PyExecutorObject *res = code->co_executors->executors[oparg]; + Py_INCREF(res); + return res; + } + i += _PyInstruction_GetLength(code, i); + } + PyErr_SetString(PyExc_ValueError, "no executor at given offset"); + return NULL; +} + /** Test support **/ @@ -287,6 +304,58 @@ uop_dealloc(_PyUOpExecutorObject *self) { PyObject_Free(self); } +static const char * +uop_name(int index) { + if (index < EXIT_TRACE) { + return _PyOpcode_OpName[index]; + } + return _PyOpcode_uop_name[index]; +} + +static Py_ssize_t +uop_len(_PyUOpExecutorObject *self) +{ + int count = 1; + for (; count < _Py_UOP_MAX_TRACE_LENGTH; count++) { + if (self->trace[count-1].opcode == EXIT_TRACE) { + break; + } + } + return count; +} + +static PyObject * +uop_item(_PyUOpExecutorObject *self, Py_ssize_t index) +{ + for (int i = 0; i < _Py_UOP_MAX_TRACE_LENGTH; i++) { + if (self->trace[i].opcode == EXIT_TRACE) { + break; + } + if (i != index) { + continue; + } + const char *name = uop_name(self->trace[i].opcode); + PyObject *oname = _PyUnicode_FromASCII(name, strlen(name)); + if (oname == NULL) { + return NULL; + } + PyObject *operand = PyLong_FromUnsignedLongLong(self->trace[i].operand); + if (operand == NULL) { + Py_DECREF(oname); + return NULL; + } + PyObject *args[2] = { oname, operand }; + return _PyTuple_FromArraySteal(args, 2); + } + PyErr_SetNone(PyExc_IndexError); + return NULL; +} + +PySequenceMethods uop_as_sequence = { + .sq_length = (lenfunc)uop_len, + .sq_item = (ssizeargfunc)uop_item, +}; + static PyTypeObject UOpExecutor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "uop_executor", @@ -294,6 +363,7 @@ static PyTypeObject UOpExecutor_Type = { .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, .tp_dealloc = (destructor)uop_dealloc, + .tp_as_sequence = &uop_as_sequence, }; static int diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 4711fbbd1eb8c3..2e841e6097aa25 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -184,14 +184,15 @@ def main(opcode_py, fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}") iobj.write("\n") - iobj.write("#ifdef Py_DEBUG\n") - iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") + iobj.write(f"\nextern const char *const _PyOpcode_OpName[{NUM_OPCODES}];\n") + iobj.write("\n#ifdef NEED_OPCODE_TABLES\n") + iobj.write(f"const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") for op, name in enumerate(opname_including_specialized): if name[0] != "<": op = name iobj.write(f''' [{op}] = "{name}",\n''') iobj.write("};\n") - iobj.write("#endif\n") + iobj.write("#endif // NEED_OPCODE_TABLES\n") iobj.write("\n") iobj.write("#define EXTRA_CASES \\\n") diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 657dfa93fd537d..a90abfe20c1739 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1224,9 +1224,7 @@ def write_metadata(self) -> None: self.out.emit("#ifndef NEED_OPCODE_METADATA") self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") - self.out.emit("#ifdef Py_DEBUG") self.out.emit("extern const char * const _PyOpcode_uop_name[512];") - self.out.emit("#endif") self.out.emit("#else") self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") @@ -1273,10 +1271,10 @@ def write_metadata(self) -> None: case _: typing.assert_never(thing) - self.out.emit("#ifdef Py_DEBUG") + self.out.emit("#ifdef NEED_OPCODE_METADATA") with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",") - self.out.emit("#endif") + self.out.emit("#endif // NEED_OPCODE_METADATA") self.out.emit("#endif") From aa85c93792876a602fc9ce2083b64958507d29bf Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Jul 2023 18:55:45 +0200 Subject: [PATCH 265/446] gh-106320: Remove _PyInterpreterState_HasFeature() (#106425) Remove the _PyInterpreterState_HasFeature() function from the C API: move it to the internal C API (pycore_interp.h). No longer export the function. --- Include/cpython/pystate.h | 32 -------------------------------- Include/internal/pycore_interp.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index e08bcdaf197628..4254110889fc6c 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -3,38 +3,6 @@ #endif -/* -Runtime Feature Flags - -Each flag indicate whether or not a specific runtime feature -is available in a given context. For example, forking the process -might not be allowed in the current interpreter (i.e. os.fork() would fail). -*/ - -/* Set if the interpreter share obmalloc runtime state - with the main interpreter. */ -#define Py_RTFLAGS_USE_MAIN_OBMALLOC (1UL << 5) - -/* Set if import should check a module for subinterpreter support. */ -#define Py_RTFLAGS_MULTI_INTERP_EXTENSIONS (1UL << 8) - -/* Set if threads are allowed. */ -#define Py_RTFLAGS_THREADS (1UL << 10) - -/* Set if daemon threads are allowed. */ -#define Py_RTFLAGS_DAEMON_THREADS (1UL << 11) - -/* Set if os.fork() is allowed. */ -#define Py_RTFLAGS_FORK (1UL << 15) - -/* Set if os.exec*() is allowed. */ -#define Py_RTFLAGS_EXEC (1UL << 16) - - -PyAPI_FUNC(int) _PyInterpreterState_HasFeature(PyInterpreterState *interp, - unsigned long feature); - - /* private interpreter helpers */ PyAPI_FUNC(int) _PyInterpreterState_RequiresIDRef(PyInterpreterState *); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index a1f00df12d6ac9..bb37cafe6286a9 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -275,6 +275,38 @@ PyAPI_FUNC(int) _PyInterpreterState_GetConfigCopy( PyAPI_FUNC(int) _PyInterpreterState_SetConfig( const struct PyConfig *config); + +/* +Runtime Feature Flags + +Each flag indicate whether or not a specific runtime feature +is available in a given context. For example, forking the process +might not be allowed in the current interpreter (i.e. os.fork() would fail). +*/ + +/* Set if the interpreter share obmalloc runtime state + with the main interpreter. */ +#define Py_RTFLAGS_USE_MAIN_OBMALLOC (1UL << 5) + +/* Set if import should check a module for subinterpreter support. */ +#define Py_RTFLAGS_MULTI_INTERP_EXTENSIONS (1UL << 8) + +/* Set if threads are allowed. */ +#define Py_RTFLAGS_THREADS (1UL << 10) + +/* Set if daemon threads are allowed. */ +#define Py_RTFLAGS_DAEMON_THREADS (1UL << 11) + +/* Set if os.fork() is allowed. */ +#define Py_RTFLAGS_FORK (1UL << 15) + +/* Set if os.exec*() is allowed. */ +#define Py_RTFLAGS_EXEC (1UL << 16) + +extern int _PyInterpreterState_HasFeature(PyInterpreterState *interp, + unsigned long feature); + + #ifdef __cplusplus } #endif From 8a4bba8b9764ba28667b137fe62c11aea672f500 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 5 Jul 2023 02:02:49 +0900 Subject: [PATCH 266/446] gh-106162: array: suppress warning in test_array (#106404) array: suppress warning in test_array --- Lib/test/test_array.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index bec3766b87b202..a219fa365e7f20 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -215,6 +215,14 @@ class BaseTest: # outside: An entry that is not in example # minitemsize: the minimum guaranteed itemsize + def setUp(self): + self.enterContext(warnings.catch_warnings()) + warnings.filterwarnings( + "ignore", + message="The 'u' type code is deprecated and " + "will be removed in Python 3.16", + category=DeprecationWarning) + def assertEntryEqual(self, entry1, entry2): self.assertEqual(entry1, entry2) From 2dfc7fae787e65726f24bfe9efe05418b05ee8e2 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Tue, 4 Jul 2023 19:34:43 +0200 Subject: [PATCH 267/446] gh-61215: Rename `wait_until_any_call` to `wait_until_any_call_with` (#106414) mock: Rename `wait_until_any_call` to `wait_until_any_call_with` Rename the method to be more explicit that it expects the args and kwargs to wait for. --- Doc/library/unittest.mock.rst | 4 +- .../testmock/testthreadingmock.py | 50 +++++++++---------- Lib/unittest/mock.py | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index 756422bd6eab9e..6d5f17d1c2c5cd 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -1126,7 +1126,7 @@ object:: >>> mock.wait_until_called(timeout=1) >>> thread.join() - .. method:: wait_until_any_call(*args, **kwargs) + .. method:: wait_until_any_call_with(*args, **kwargs) Waits until the the mock is called with the specified arguments. @@ -1136,7 +1136,7 @@ object:: >>> mock = ThreadingMock() >>> thread = threading.Thread(target=mock, args=("arg1", "arg2",), kwargs={"arg": "thing"}) >>> thread.start() - >>> mock.wait_until_any_call("arg1", "arg2", arg="thing") + >>> mock.wait_until_any_call_with("arg1", "arg2", arg="thing") >>> thread.join() .. attribute:: DEFAULT_TIMEOUT diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py index 6219cc58abdc44..2b4dca3a4be179 100644 --- a/Lib/test/test_unittest/testmock/testthreadingmock.py +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -87,7 +87,7 @@ def test_no_name_clash(self): waitable_mock.timeout = "mytimeout" waitable_mock("works") waitable_mock.wait_until_called() - waitable_mock.wait_until_any_call("works") + waitable_mock.wait_until_any_call_with("works") def test_wait_success(self): waitable_mock = self._make_mock(spec=Something) @@ -96,7 +96,7 @@ def test_wait_success(self): something = Something() self.run_async(something.method_1, delay=0.01) something.method_1.wait_until_called() - something.method_1.wait_until_any_call() + something.method_1.wait_until_any_call_with() something.method_1.assert_called() def test_wait_success_with_instance_timeout(self): @@ -106,7 +106,7 @@ def test_wait_success_with_instance_timeout(self): something = Something() self.run_async(something.method_1, delay=0.01) something.method_1.wait_until_called() - something.method_1.wait_until_any_call() + something.method_1.wait_until_any_call_with() something.method_1.assert_called() def test_wait_failed_with_instance_timeout(self): @@ -117,7 +117,7 @@ def test_wait_failed_with_instance_timeout(self): self.run_async(something.method_1, delay=0.5) self.assertRaises(AssertionError, waitable_mock.method_1.wait_until_called) self.assertRaises( - AssertionError, waitable_mock.method_1.wait_until_any_call + AssertionError, waitable_mock.method_1.wait_until_any_call_with ) def test_wait_success_with_timeout_override(self): @@ -137,7 +137,7 @@ def test_wait_failed_with_timeout_override(self): with self.assertRaises(AssertionError): something.method_1.wait_until_called(timeout=0.05) with self.assertRaises(AssertionError): - something.method_1.wait_until_any_call(timeout=0.05) + something.method_1.wait_until_any_call_with(timeout=0.05) def test_wait_success_called_before(self): waitable_mock = self._make_mock() @@ -146,7 +146,7 @@ def test_wait_success_called_before(self): something = Something() something.method_1() something.method_1.wait_until_called() - something.method_1.wait_until_any_call() + something.method_1.wait_until_any_call_with() something.method_1.assert_called() def test_wait_magic_method(self): @@ -158,7 +158,7 @@ def test_wait_magic_method(self): something.method_1.__str__.wait_until_called() something.method_1.__str__.assert_called() - def test_wait_until_any_call_positional(self): + def test_wait_until_any_call_with_positional(self): waitable_mock = self._make_mock(spec=Something) with patch(f"{__name__}.Something", waitable_mock): @@ -168,16 +168,16 @@ def test_wait_until_any_call_positional(self): self.run_async(something.method_1, 3, delay=0.3) self.assertNotIn(call(1), something.method_1.mock_calls) - something.method_1.wait_until_any_call(1) + something.method_1.wait_until_any_call_with(1) something.method_1.assert_called_with(1) self.assertNotIn(call(2), something.method_1.mock_calls) self.assertNotIn(call(3), something.method_1.mock_calls) - something.method_1.wait_until_any_call(3) + something.method_1.wait_until_any_call_with(3) self.assertIn(call(2), something.method_1.mock_calls) - something.method_1.wait_until_any_call(2) + something.method_1.wait_until_any_call_with(2) - def test_wait_until_any_call_keywords(self): + def test_wait_until_any_call_with_keywords(self): waitable_mock = self._make_mock(spec=Something) with patch(f"{__name__}.Something", waitable_mock): @@ -187,16 +187,16 @@ def test_wait_until_any_call_keywords(self): self.run_async(something.method_1, c=3, delay=0.3) self.assertNotIn(call(a=1), something.method_1.mock_calls) - something.method_1.wait_until_any_call(a=1) + something.method_1.wait_until_any_call_with(a=1) something.method_1.assert_called_with(a=1) self.assertNotIn(call(b=2), something.method_1.mock_calls) self.assertNotIn(call(c=3), something.method_1.mock_calls) - something.method_1.wait_until_any_call(c=3) + something.method_1.wait_until_any_call_with(c=3) self.assertIn(call(b=2), something.method_1.mock_calls) - something.method_1.wait_until_any_call(b=2) + something.method_1.wait_until_any_call_with(b=2) - def test_wait_until_any_call_no_argument_fails_when_called_with_arg(self): + def test_wait_until_any_call_with_no_argument_fails_when_called_with_arg(self): waitable_mock = self._make_mock(timeout=0.01) with patch(f"{__name__}.Something", waitable_mock): @@ -205,25 +205,25 @@ def test_wait_until_any_call_no_argument_fails_when_called_with_arg(self): something.method_1.assert_called_with(1) with self.assertRaises(AssertionError): - something.method_1.wait_until_any_call() + something.method_1.wait_until_any_call_with() something.method_1() - something.method_1.wait_until_any_call() + something.method_1.wait_until_any_call_with() - def test_wait_until_any_call_global_default(self): + def test_wait_until_any_call_with_global_default(self): with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): ThreadingMock.DEFAULT_TIMEOUT = 0.01 m = self._make_mock() with self.assertRaises(AssertionError): - m.wait_until_any_call() + m.wait_until_any_call_with() with self.assertRaises(AssertionError): m.wait_until_called() m() - m.wait_until_any_call() + m.wait_until_any_call_with() assert ThreadingMock.DEFAULT_TIMEOUT != 0.01 - def test_wait_until_any_call_change_global_and_override(self): + def test_wait_until_any_call_with_change_global_and_override(self): with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): ThreadingMock.DEFAULT_TIMEOUT = 0.01 @@ -256,10 +256,10 @@ def test_reset_mock_resets_wait(self): with self.assertRaises(AssertionError): m.wait_until_called() with self.assertRaises(AssertionError): - m.wait_until_any_call() + m.wait_until_any_call_with() m() m.wait_until_called() - m.wait_until_any_call() + m.wait_until_any_call_with() m.assert_called_once() m.reset_mock() @@ -267,10 +267,10 @@ def test_reset_mock_resets_wait(self): with self.assertRaises(AssertionError): m.wait_until_called() with self.assertRaises(AssertionError): - m.wait_until_any_call() + m.wait_until_any_call_with() m() m.wait_until_called() - m.wait_until_any_call() + m.wait_until_any_call_with() m.assert_called_once() diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index b542a9a2c51a9f..7ef7e7180b31c2 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -3070,7 +3070,7 @@ def wait_until_called(self, *, timeout=_timeout_unset): f" timeout({timeout}).") raise AssertionError(msg) - def wait_until_any_call(self, *args, **kwargs): + def wait_until_any_call_with(self, *args, **kwargs): """Wait until the mock object is called with given args. Waits for the timeout in seconds provided in the constructor. From c5dacc8fa0c3013be8b457afac996bdae1dc12d2 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 4 Jul 2023 21:20:00 +0300 Subject: [PATCH 268/446] gh-106217: Truncate the issue body size of `new-bugs-announce-notifier` (#106423) --- .github/workflows/new-bugs-announce-notifier.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml index e3572db670693e..80514b4d2ca572 100644 --- a/.github/workflows/new-bugs-announce-notifier.yml +++ b/.github/workflows/new-bugs-announce-notifier.yml @@ -44,7 +44,7 @@ jobs: // We need to truncate the body size, because the max size for // the whole payload is 16kb. We want to be safe and assume that // body can take up to ~8kb of space. - body : issue.data.body.substring(8000) + body : issue.data.body.substring(0, 8000) }; const data = { From eeb5c63179eba0390c8937d0803a41092225be7e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 4 Jul 2023 20:45:32 +0100 Subject: [PATCH 269/446] Add some codeowners for `Tools/clinic/` (#106430) Co-authored-by: Erlend E. Aasland --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c044e9b8f88c58..5b471c79f75eea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -173,3 +173,7 @@ Doc/c-api/stable.rst @encukou # zipfile.Path **/*zipfile/*_path.py @jaraco + +# Argument Clinic +/Tools/clinic/** @erlend-aasland @AlexWaygood +/Lib/test/test_clinic.py @erlend-aasland @AlexWaygood From 17af98227f883a93bfbd866b4bcc719ba9d682a1 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 4 Jul 2023 14:42:12 -0700 Subject: [PATCH 270/446] gh-106320: Fix specialize.c compilation by including pycore_pylifecycle.h (#106434) Compilation of Python/specialize.c was broken on macOS for me by gh-106400. --- Python/specialize.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/specialize.c b/Python/specialize.c index 22c58e2c46fc36..a3fce2e6775912 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -9,6 +9,7 @@ #include "pycore_opcode.h" // _PyOpcode_Caches #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #include "pycore_descrobject.h" +#include "pycore_pylifecycle.h" // _PyOS_URandomNonblock() #include // rand() From 110b97c94ce2544dc731298e35dfb003d58af626 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 00:13:30 +0200 Subject: [PATCH 271/446] gh-104050: Annotate toplevel functions in clinic.py (#106435) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 63 +++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index c02c82876591f8..3d18d9560bc28b 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -575,7 +575,7 @@ def permute_optional_groups(left, required, right): return tuple(accumulator) -def strip_leading_and_trailing_blank_lines(s): +def strip_leading_and_trailing_blank_lines(s: str) -> str: lines = s.rstrip().split('\n') while lines: line = lines[0] @@ -585,7 +585,11 @@ def strip_leading_and_trailing_blank_lines(s): return '\n'.join(lines) @functools.lru_cache() -def normalize_snippet(s, *, indent=0): +def normalize_snippet( + s: str, + *, + indent: int = 0 +) -> str: """ Reformats s: * removes leading and trailing blank lines @@ -599,7 +603,11 @@ def normalize_snippet(s, *, indent=0): return s -def declare_parser(f, *, hasformat=False): +def declare_parser( + f: Function, + *, + hasformat: bool = False +) -> str: """ Generates the code template for a static local PyArg_Parser variable, with an initializer. For core code (incl. builtin modules) the @@ -658,7 +666,10 @@ def declare_parser(f, *, hasformat=False): return normalize_snippet(declarations) -def wrap_declarations(text, length=78): +def wrap_declarations( + text: str, + length: int = 78 +) -> str: """ A simple-minded text wrapper for C function declarations. @@ -680,14 +691,14 @@ def wrap_declarations(text, length=78): if not after_l_paren: lines.append(line) continue - parameters, _, after_r_paren = after_l_paren.partition(')') + in_paren, _, after_r_paren = after_l_paren.partition(')') if not _: lines.append(line) continue - if ',' not in parameters: + if ',' not in in_paren: lines.append(line) continue - parameters = [x.strip() + ", " for x in parameters.split(',')] + parameters = [x.strip() + ", " for x in in_paren.split(',')] prefix += "(" if len(prefix) < length: spaces = " " * len(prefix) @@ -1589,7 +1600,12 @@ def OverrideStdioWith(stdout): sys.stdout = saved_stdout -def create_regex(before, after, word=True, whole_line=True): +def create_regex( + before: str, + after: str, + word: bool = True, + whole_line: bool = True +) -> re.Pattern[str]: """Create an re object for matching marker lines.""" group_re = r"\w+" if word else ".+" pattern = r'{}({}){}' @@ -1985,7 +2001,7 @@ def file_changed(filename: str, new_contents: str) -> bool: return True -def write_file(filename: str, new_contents: str): +def write_file(filename: str, new_contents: str) -> None: # Atomic write using a temporary file and os.replace() filename_new = f"{filename}.new" with open(filename_new, "w", encoding="utf-8") as fp: @@ -2602,7 +2618,10 @@ def __getattribute__(self, name: str): fail("Stepped on a land mine, trying to access attribute " + repr(name) + ":\n" + self.__message__) -def add_c_converter(f, name=None): +def add_c_converter( + f: type[CConverter], + name: str | None = None +) -> type[CConverter]: if not name: name = f.__name__ if not name.endswith('_converter'): @@ -2620,7 +2639,10 @@ def add_default_legacy_c_converter(cls): legacy_converters[cls.format_unit] = cls return cls -def add_legacy_c_converter(format_unit, **kwargs): +def add_legacy_c_converter( + format_unit: str, + **kwargs +) -> Callable[[ConverterType], ConverterType]: """ Adds a legacy converter. """ @@ -3887,7 +3909,9 @@ def parse_arg(self, argname: str, displayname: str) -> str: return super().parse_arg(argname, displayname) -def correct_name_for_self(f) -> tuple[str, str]: +def correct_name_for_self( + f: Function +) -> tuple[str, str]: if f.kind in (CALLABLE, METHOD_INIT): if f.cls: return "PyObject *", "self" @@ -3898,7 +3922,9 @@ def correct_name_for_self(f) -> tuple[str, str]: return "PyTypeObject *", "type" raise RuntimeError("Unhandled type of function f: " + repr(f.kind)) -def required_type_for_self_for_parser(f): +def required_type_for_self_for_parser( + f: Function +) -> str | None: type, _ = correct_name_for_self(f) if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD): return type @@ -4193,7 +4219,12 @@ class float_return_converter(double_return_converter): cast = '(double)' -def eval_ast_expr(node, globals, *, filename='-'): +def eval_ast_expr( + node: ast.expr, + globals: dict[str, Any], + *, + filename: str = '-' +) -> FunctionType: """ Takes an ast.Expr node. Compiles and evaluates it. Returns the result of the expression. @@ -4205,8 +4236,8 @@ def eval_ast_expr(node, globals, *, filename='-'): if isinstance(node, ast.Expr): node = node.value - node = ast.Expression(node) - co = compile(node, filename, 'eval') + expr = ast.Expression(node) + co = compile(expr, filename, 'eval') fn = FunctionType(co, globals) return fn() From 22087516bca0b339a04742765febc9c20a9d6b21 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 00:15:10 +0200 Subject: [PATCH 272/446] gh-104050: Annotate Argument Clinic parameter permutation helpers (#106431) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 3d18d9560bc28b..898361474f7214 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -28,7 +28,12 @@ import textwrap import traceback -from collections.abc import Callable +from collections.abc import ( + Callable, + Iterable, + Iterator, + Sequence, +) from types import FunctionType, NoneType from typing import ( Any, @@ -516,7 +521,13 @@ class PythonLanguage(Language): checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/" -def permute_left_option_groups(l): +ParamGroup = Iterable["Parameter"] +ParamTuple = tuple["Parameter", ...] + + +def permute_left_option_groups( + l: Sequence[ParamGroup] +) -> Iterator[ParamTuple]: """ Given [(1,), (2,), (3,)], should yield: () @@ -525,13 +536,15 @@ def permute_left_option_groups(l): (1, 2, 3) """ yield tuple() - accumulator = [] + accumulator: list[Parameter] = [] for group in reversed(l): accumulator = list(group) + accumulator yield tuple(accumulator) -def permute_right_option_groups(l): +def permute_right_option_groups( + l: Sequence[ParamGroup] +) -> Iterator[ParamTuple]: """ Given [(1,), (2,), (3,)], should yield: () @@ -540,13 +553,17 @@ def permute_right_option_groups(l): (1, 2, 3) """ yield tuple() - accumulator = [] + accumulator: list[Parameter] = [] for group in l: accumulator.extend(group) yield tuple(accumulator) -def permute_optional_groups(left, required, right): +def permute_optional_groups( + left: Sequence[ParamGroup], + required: ParamGroup, + right: Sequence[ParamGroup] +) -> tuple[ParamTuple, ...]: """ Generator function that computes the set of acceptable argument lists for the provided iterables of @@ -561,7 +578,7 @@ def permute_optional_groups(left, required, right): if left: raise ValueError("required is empty but left is not") - accumulator = [] + accumulator: list[ParamTuple] = [] counts = set() for r in permute_right_option_groups(right): for l in permute_left_option_groups(left): From 2fb9480c8313ab524d333b18e4af09f05f5b8afa Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 00:35:57 +0200 Subject: [PATCH 273/446] gh-106368: Add tests for formatting helpers in Argument Clinic (#106415) Co-authored-by: Alex Waygood --- Lib/test/test_clinic.py | 164 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 544e7323e4f606..c095d14234375f 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1692,5 +1692,169 @@ def test_permute_optional_groups(self): self.assertEqual(actual, expected) +class FormatHelperTests(unittest.TestCase): + + def test_strip_leading_and_trailing_blank_lines(self): + dataset = ( + # Input lines, expected output. + ("a\nb", "a\nb"), + ("a\nb\n", "a\nb"), + ("a\nb ", "a\nb"), + ("\na\nb\n\n", "a\nb"), + ("\n\na\nb\n\n", "a\nb"), + ("\n\na\n\nb\n\n", "a\n\nb"), + # Note, leading whitespace is preserved: + (" a\nb", " a\nb"), + (" a\nb ", " a\nb"), + (" \n \n a\nb \n \n ", " a\nb"), + ) + for lines, expected in dataset: + with self.subTest(lines=lines, expected=expected): + out = clinic.strip_leading_and_trailing_blank_lines(lines) + self.assertEqual(out, expected) + + def test_normalize_snippet(self): + snippet = """ + one + two + three + """ + + # Expected outputs: + zero_indent = ( + "one\n" + "two\n" + "three" + ) + four_indent = ( + " one\n" + " two\n" + " three" + ) + eight_indent = ( + " one\n" + " two\n" + " three" + ) + expected_outputs = {0: zero_indent, 4: four_indent, 8: eight_indent} + for indent, expected in expected_outputs.items(): + with self.subTest(indent=indent): + actual = clinic.normalize_snippet(snippet, indent=indent) + self.assertEqual(actual, expected) + + def test_accumulator(self): + acc = clinic.text_accumulator() + self.assertEqual(acc.output(), "") + acc.append("a") + self.assertEqual(acc.output(), "a") + self.assertEqual(acc.output(), "") + acc.append("b") + self.assertEqual(acc.output(), "b") + self.assertEqual(acc.output(), "") + acc.append("c") + acc.append("d") + self.assertEqual(acc.output(), "cd") + self.assertEqual(acc.output(), "") + + def test_quoted_for_c_string(self): + dataset = ( + # input, expected + (r"abc", r"abc"), + (r"\abc", r"\\abc"), + (r"\a\bc", r"\\a\\bc"), + (r"\a\\bc", r"\\a\\\\bc"), + (r'"abc"', r'\"abc\"'), + (r"'a'", r"\'a\'"), + ) + for line, expected in dataset: + with self.subTest(line=line, expected=expected): + out = clinic.quoted_for_c_string(line) + self.assertEqual(out, expected) + + def test_rstrip_lines(self): + lines = ( + "a \n" + "b\n" + " c\n" + " d \n" + ) + expected = ( + "a\n" + "b\n" + " c\n" + " d\n" + ) + out = clinic.rstrip_lines(lines) + self.assertEqual(out, expected) + + def test_format_escape(self): + line = "{}, {a}" + expected = "{{}}, {{a}}" + out = clinic.format_escape(line) + self.assertEqual(out, expected) + + def test_indent_all_lines(self): + # Blank lines are expected to be unchanged. + self.assertEqual(clinic.indent_all_lines("", prefix="bar"), "") + + lines = ( + "one\n" + "two" # The missing newline is deliberate. + ) + expected = ( + "barone\n" + "bartwo" + ) + out = clinic.indent_all_lines(lines, prefix="bar") + self.assertEqual(out, expected) + + # If last line is empty, expect it to be unchanged. + lines = ( + "\n" + "one\n" + "two\n" + "" + ) + expected = ( + "bar\n" + "barone\n" + "bartwo\n" + "" + ) + out = clinic.indent_all_lines(lines, prefix="bar") + self.assertEqual(out, expected) + + def test_suffix_all_lines(self): + # Blank lines are expected to be unchanged. + self.assertEqual(clinic.suffix_all_lines("", suffix="foo"), "") + + lines = ( + "one\n" + "two" # The missing newline is deliberate. + ) + expected = ( + "onefoo\n" + "twofoo" + ) + out = clinic.suffix_all_lines(lines, suffix="foo") + self.assertEqual(out, expected) + + # If last line is empty, expect it to be unchanged. + lines = ( + "\n" + "one\n" + "two\n" + "" + ) + expected = ( + "foo\n" + "onefoo\n" + "twofoo\n" + "" + ) + out = clinic.suffix_all_lines(lines, suffix="foo") + self.assertEqual(out, expected) + + if __name__ == "__main__": unittest.main() From 7bb9fa5ae486912d5d0a9372f213ba6a72c4cde1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 01:07:57 +0200 Subject: [PATCH 274/446] gh-104050: Partially annotate Argument Clinic CLanguage class (#106437) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 898361474f7214..5f5d024b5aa6f8 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -752,10 +752,14 @@ def __init__(self, filename): self.cpp = cpp.Monitor(filename) self.cpp.fail = fail - def parse_line(self, line): + def parse_line(self, line: str) -> None: self.cpp.writeline(line) - def render(self, clinic, signatures): + def render( + self, + clinic: Clinic | None, + signatures: Iterable[Function] + ) -> str: function = None for o in signatures: if isinstance(o, Function): @@ -764,7 +768,10 @@ def render(self, clinic, signatures): function = o return self.render_function(clinic, function) - def docstring_for_c_string(self, f): + def docstring_for_c_string( + self, + f: Function + ) -> str: if re.search(r'[^\x00-\x7F]', f.docstring): warn("Non-ascii character appear in docstring.") @@ -1345,7 +1352,7 @@ def parser_body(prototype, *fields, declarations=''): return d2 @staticmethod - def group_to_variable_name(group): + def group_to_variable_name(group: int) -> str: adjective = "left_" if group < 0 else "right_" return "group_" + adjective + str(abs(group)) @@ -1441,8 +1448,12 @@ def render_option_group_parsing(self, f, template_dict): add("}") template_dict['option_group_parsing'] = format_escape(output()) - def render_function(self, clinic, f): - if not f: + def render_function( + self, + clinic: Clinic | None, + f: Function | None + ) -> str: + if f is None or clinic is None: return "" add, output = text_accumulator() @@ -1504,10 +1515,12 @@ def render_function(self, clinic, f): template_dict = {} + assert isinstance(f.full_name, str) full_name = f.full_name template_dict['full_name'] = full_name if new_or_init: + assert isinstance(f.cls, Class) name = f.cls.name else: name = f.name From ad075682ba49c3d90cb9b09341f8bf2ea56761d8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 4 Jul 2023 22:08:25 -0700 Subject: [PATCH 275/446] tp_flags docs: fix indentation (#106420) --- Doc/c-api/typeobj.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index c6e783acdf0654..239c191457f516 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1143,14 +1143,14 @@ and :c:type:`PyType_Type` effectively act as defaults.) :const:`Py_TPFLAGS_IMMUTABLETYPE` flag set. For extension types, it is inherited whenever :c:member:`~PyTypeObject.tp_descr_get` is inherited. - .. data:: Py_TPFLAGS_MANAGED_DICT + .. data:: Py_TPFLAGS_MANAGED_DICT - This bit indicates that instances of the class have a ``__dict__`` - attribute, and that the space for the dictionary is managed by the VM. + This bit indicates that instances of the class have a ``__dict__`` + attribute, and that the space for the dictionary is managed by the VM. - If this flag is set, :const:`Py_TPFLAGS_HAVE_GC` should also be set. + If this flag is set, :const:`Py_TPFLAGS_HAVE_GC` should also be set. - .. versionadded:: 3.12 + .. versionadded:: 3.12 **Inheritance:** @@ -1158,12 +1158,12 @@ and :c:type:`PyType_Type` effectively act as defaults.) :c:member:`~PyTypeObject.tp_dictoffset` field is set in a superclass. - .. data:: Py_TPFLAGS_MANAGED_WEAKREF + .. data:: Py_TPFLAGS_MANAGED_WEAKREF - This bit indicates that instances of the class should be weakly - referenceable. + This bit indicates that instances of the class should be weakly + referenceable. - .. versionadded:: 3.12 + .. versionadded:: 3.12 **Inheritance:** From a941bd6c53ac4646926292557a7bb2a86f8025c3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 10:33:05 +0200 Subject: [PATCH 276/446] gh-104683: Rename Lib/test/clinic.test as Lib/test/clinic.test.c (#106443) --- Lib/test/{clinic.test => clinic.test.c} | 0 Lib/test/test_clinic.py | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename Lib/test/{clinic.test => clinic.test.c} (100%) diff --git a/Lib/test/clinic.test b/Lib/test/clinic.test.c similarity index 100% rename from Lib/test/clinic.test rename to Lib/test/clinic.test.c diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index c095d14234375f..7c46e8a81803a2 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1089,15 +1089,16 @@ class ClinicExternalTest(TestCase): maxDiff = None def test_external(self): + CLINIC_TEST = 'clinic.test.c' # bpo-42398: Test that the destination file is left unchanged if the # content does not change. Moreover, check also that the file # modification time does not change in this case. - source = support.findfile('clinic.test') + source = support.findfile(CLINIC_TEST) with open(source, 'r', encoding='utf-8') as f: orig_contents = f.read() with os_helper.temp_dir() as tmp_dir: - testfile = os.path.join(tmp_dir, 'clinic.test.c') + testfile = os.path.join(tmp_dir, CLINIC_TEST) with open(testfile, 'w', encoding='utf-8') as f: f.write(orig_contents) old_mtime_ns = os.stat(testfile).st_mtime_ns From 9d1d4f9c73a71192b22ab52a2eb9278737f98ddb Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 5 Jul 2023 13:23:22 +0200 Subject: [PATCH 277/446] gh-64595: Fix regression in file write logic in Argument Clinic (#106449) Revert the two commits that introduced the regressions: - gh-104152 - gh-104507 --- Lib/test/test_clinic.py | 7 +++---- Tools/clinic/clinic.py | 35 ++++++++++++----------------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 7c46e8a81803a2..685ba58642a5ae 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -100,9 +100,8 @@ def test_eol(self): # the last line of the block got corrupted. c = clinic.Clinic(clinic.CLanguage(None), filename="file") raw = "/*[clinic]\nfoo\n[clinic]*/" - cooked, _ = c.parse(raw) - lines = cooked.splitlines() - end_line = lines[2].rstrip() + cooked = c.parse(raw).splitlines() + end_line = cooked[2].rstrip() # this test is redundant, it's just here explicitly to catch # the regression test so we don't forget what it looked like self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") @@ -261,7 +260,7 @@ def _test_clinic(self, input, output): c = clinic.Clinic(language, filename="file") c.parsers['inert'] = InertParser(c) c.parsers['copy'] = CopyParser(c) - computed, _ = c.parse(input) + computed = c.parse(input) self.assertEqual(output, computed) def test_clinic_1(self): diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 5f5d024b5aa6f8..7ada7e9d917b38 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2021,22 +2021,20 @@ def dump(self): extensions['py'] = PythonLanguage -def file_changed(filename: str, new_contents: str) -> bool: - """Return true if file contents changed (meaning we must update it)""" +def write_file(filename: str, new_contents: str) -> None: try: - with open(filename, encoding="utf-8") as fp: + with open(filename, 'r', encoding="utf-8") as fp: old_contents = fp.read() - return old_contents != new_contents - except FileNotFoundError: - return True - -def write_file(filename: str, new_contents: str) -> None: + if old_contents == new_contents: + # no change: avoid modifying the file modification time + return + except FileNotFoundError: + pass # Atomic write using a temporary file and os.replace() filename_new = f"{filename}.new" with open(filename_new, "w", encoding="utf-8") as fp: fp.write(new_contents) - try: os.replace(filename_new, filename) except: @@ -2214,8 +2212,6 @@ def parse(self, input): traceback.format_exc().rstrip()) printer.print_block(block) - clinic_out = [] - # these are destinations not buffers for name, destination in self.destinations.items(): if destination.type == 'suppress': @@ -2223,7 +2219,6 @@ def parse(self, input): output = destination.dump() if output: - block = Block("", dsl_name="clinic", output=output) if destination.type == 'buffer': @@ -2255,11 +2250,10 @@ def parse(self, input): block.input = 'preserve\n' printer_2 = BlockPrinter(self.language) printer_2.print_block(block, core_includes=True) - pair = destination.filename, printer_2.f.getvalue() - clinic_out.append(pair) + write_file(destination.filename, printer_2.f.getvalue()) continue - return printer.f.getvalue(), clinic_out + return printer.f.getvalue() def _module_and_class(self, fields): @@ -2321,14 +2315,9 @@ def parse_file( assert isinstance(language, CLanguage) clinic = Clinic(language, verify=verify, filename=filename) - src_out, clinic_out = clinic.parse(raw) - - changes = [(fn, data) for fn, data in clinic_out if file_changed(fn, data)] - if changes: - # Always (re)write the source file. - write_file(output, src_out) - for fn, data in clinic_out: - write_file(fn, data) + cooked = clinic.parse(raw) + + write_file(output, cooked) def compute_checksum( From 12a98138083589314d3da14bc97f2d8517947437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Wed, 5 Jul 2023 15:07:02 +0000 Subject: [PATCH 278/446] Clarify state of CancelledError in doc (#106453) This change makes it explicit that asyncio.CancelledError is not a subclass of Exception. --- Doc/library/asyncio-exceptions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/asyncio-exceptions.rst b/Doc/library/asyncio-exceptions.rst index 9250f01b8a0895..7ad9103ca3fdfc 100644 --- a/Doc/library/asyncio-exceptions.rst +++ b/Doc/library/asyncio-exceptions.rst @@ -31,7 +31,7 @@ Exceptions .. versionchanged:: 3.8 - :exc:`CancelledError` is now a subclass of :class:`BaseException`. + :exc:`CancelledError` is now a subclass of :class:`BaseException` rather than :class:`Exception`. .. exception:: InvalidStateError From 70e2a42647f2f4b53d0f07c0c7db48ea27e066fa Mon Sep 17 00:00:00 2001 From: JosephSBoyle <48555120+JosephSBoyle@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:17:37 +0100 Subject: [PATCH 279/446] gh-102542 Remove unused bytes object and bytes slicing (#106433) Remove unused bytes object and bytes slicing Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/email/mime/audio.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Lib/email/mime/audio.py b/Lib/email/mime/audio.py index 065819b2a2101d..aa0c4905cbb2b4 100644 --- a/Lib/email/mime/audio.py +++ b/Lib/email/mime/audio.py @@ -6,7 +6,6 @@ __all__ = ['MIMEAudio'] -from io import BytesIO from email import encoders from email.mime.nonmultipart import MIMENonMultipart @@ -59,10 +58,8 @@ def _what(data): # sndhdr.what() had a pretty cruddy interface, unfortunately. This is why # we re-do it here. It would be easier to reverse engineer the Unix 'file' # command and use the standard 'magic' file, as shipped with a modern Unix. - hdr = data[:512] - fakefile = BytesIO(hdr) for testfn in _rules: - if res := testfn(hdr, fakefile): + if res := testfn(data): return res else: return None @@ -74,7 +71,7 @@ def rule(rulefunc): @rule -def _aiff(h, f): +def _aiff(h): if not h.startswith(b'FORM'): return None if h[8:12] in {b'AIFC', b'AIFF'}: @@ -84,7 +81,7 @@ def _aiff(h, f): @rule -def _au(h, f): +def _au(h): if h.startswith(b'.snd'): return 'basic' else: @@ -92,7 +89,7 @@ def _au(h, f): @rule -def _wav(h, f): +def _wav(h): # 'RIFF' 'WAVE' 'fmt ' if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ': return None From c16ea94abc73c0098b484f7e2ec23bfd9c36b67c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 5 Jul 2023 13:38:53 -0700 Subject: [PATCH 280/446] shlex docs: remove outdated note (#106463) As the versionchanged notice says, this note is no longer true on 3.12+. --- Doc/library/shlex.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Doc/library/shlex.rst b/Doc/library/shlex.rst index 0bad51833aae13..f94833ad5331a9 100644 --- a/Doc/library/shlex.rst +++ b/Doc/library/shlex.rst @@ -30,12 +30,6 @@ The :mod:`shlex` module defines the following functions: in POSIX mode by default, but uses non-POSIX mode if the *posix* argument is false. - .. note:: - - Since the :func:`split` function instantiates a :class:`~shlex.shlex` - instance, passing ``None`` for *s* will read the string to split from - standard input. - .. versionchanged:: 3.12 Passing ``None`` for *s* argument now raises an exception, rather than reading :data:`sys.stdin`. From 217f47d6e5e56bca78b8556e910cd00890f6f84a Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 6 Jul 2023 07:19:49 +0900 Subject: [PATCH 281/446] gh-96844: Improve error message of list.remove (gh-106455) --- Doc/library/doctest.rst | 6 +++--- Lib/test/test_xml_etree.py | 2 +- .../2023-07-06-00-35-44.gh-issue-96844.kwvoS-.rst | 1 + Objects/listobject.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-06-00-35-44.gh-issue-96844.kwvoS-.rst diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index d6e4dca0860671..92da6133f9bf09 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -409,10 +409,10 @@ Simple example:: >>> [1, 2, 3].remove(42) Traceback (most recent call last): File "", line 1, in - ValueError: list.remove(x): x not in list + ValueError: 42 is not in list -That doctest succeeds if :exc:`ValueError` is raised, with the ``list.remove(x): -x not in list`` detail as shown. +That doctest succeeds if :exc:`ValueError` is raised, with the ``42 is not in list`` +detail as shown. The expected output for an exception must start with a traceback header, which may be either of the following two lines, indented the same as the first line of diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 11efee00582e01..b9352cb865d027 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -328,7 +328,7 @@ def test_simpleops(self): self.serialize_check(element, '') # 5 with self.assertRaises(ValueError) as cm: element.remove(subelement) - self.assertEqual(str(cm.exception), 'list.remove(x): x not in list') + self.assertIn('not in list', str(cm.exception)) self.serialize_check(element, '') # 6 element[0:0] = [subelement, subelement, subelement] self.serialize_check(element[1], '') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-06-00-35-44.gh-issue-96844.kwvoS-.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-06-00-35-44.gh-issue-96844.kwvoS-.rst new file mode 100644 index 00000000000000..55334173bc002d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-06-00-35-44.gh-issue-96844.kwvoS-.rst @@ -0,0 +1 @@ +Improve error message of :meth:`list.remove`. Patch by Dong-hee Na. diff --git a/Objects/listobject.c b/Objects/listobject.c index 98fa08962b6aad..144ede6351e03c 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2694,7 +2694,7 @@ list_remove(PyListObject *self, PyObject *value) else if (cmp < 0) return NULL; } - PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list"); + PyErr_Format(PyExc_ValueError, "%R is not in list", value); return NULL; } From 838406b4fc044c0b2f397c23275c69f16a76205b Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Wed, 5 Jul 2023 17:01:35 -0600 Subject: [PATCH 282/446] gh-106292: restore checking __dict__ in cached_property.__get__ (#106380) * gh-106292: restore checking __dict__ in cached_property.__get__ Co-authored-by: Dong-hee Na --- Lib/functools.py | 23 +++++++++++-------- Lib/test/test_functools.py | 19 +++++++++++++++ ...-07-03-15-09-44.gh-issue-106292.3npldV.rst | 4 ++++ 3 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst diff --git a/Lib/functools.py b/Lib/functools.py index 4d5e2709007843..8518450a8d499d 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -957,9 +957,10 @@ def __isabstractmethod__(self): ################################################################################ -### cached_property() - computed once per instance, cached as attribute +### cached_property() - property result cached as instance attribute ################################################################################ +_NOT_FOUND = object() class cached_property: def __init__(self, func): @@ -990,15 +991,17 @@ def __get__(self, instance, owner=None): f"instance to cache {self.attrname!r} property." ) raise TypeError(msg) from None - val = self.func(instance) - try: - cache[self.attrname] = val - except TypeError: - msg = ( - f"The '__dict__' attribute on {type(instance).__name__!r} instance " - f"does not support item assignment for caching {self.attrname!r} property." - ) - raise TypeError(msg) from None + val = cache.get(self.attrname, _NOT_FOUND) + if val is _NOT_FOUND: + val = self.func(instance) + try: + cache[self.attrname] = val + except TypeError: + msg = ( + f"The '__dict__' attribute on {type(instance).__name__!r} instance " + f"does not support item assignment for caching {self.attrname!r} property." + ) + raise TypeError(msg) from None return val __class_getitem__ = classmethod(GenericAlias) diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index d668fa4c3adf5c..c4eca0f5b79511 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -3037,6 +3037,25 @@ def test_access_from_class(self): def test_doc(self): self.assertEqual(CachedCostItem.cost.__doc__, "The cost of the item.") + def test_subclass_with___set__(self): + """Caching still works for a subclass defining __set__.""" + class readonly_cached_property(py_functools.cached_property): + def __set__(self, obj, value): + raise AttributeError("read only property") + + class Test: + def __init__(self, prop): + self._prop = prop + + @readonly_cached_property + def prop(self): + return self._prop + + t = Test(1) + self.assertEqual(t.prop, 1) + t._prop = 999 + self.assertEqual(t.prop, 1) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst b/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst new file mode 100644 index 00000000000000..233509344d509b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-03-15-09-44.gh-issue-106292.3npldV.rst @@ -0,0 +1,4 @@ +Check for an instance-dict cached value in the :meth:`__get__` method of +:func:`functools.cached_property`. This better matches the pre-3.12 behavior +and improves compatibility for users subclassing +:func:`functools.cached_property` and adding a :meth:`__set__` method. From 104d7b760fed18055e4f04e5da3ca619e28bfc81 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Wed, 5 Jul 2023 17:05:02 -0600 Subject: [PATCH 283/446] gh-105340: include hidden fast-locals in locals() (#105715) * gh-105340: include hidden fast-locals in locals() --- Include/internal/pycore_ceval.h | 1 + Include/internal/pycore_frame.h | 3 + Lib/test/test_listcomps.py | 22 +++++ ...-06-12-16-38-31.gh-issue-105340._jRHXe.rst | 2 + Objects/frameobject.c | 65 ++++++++++++-- Objects/object.c | 7 +- Python/bltinmodule.c | 87 +++++++++++-------- Python/ceval.c | 13 +++ 8 files changed, 158 insertions(+), 42 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 46bc18cff86d5a..e729904ff2c4cc 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -156,6 +156,7 @@ extern PyObject* _Py_MakeCoro(PyFunctionObject *func); and asynchronous exception */ extern int _Py_HandlePending(PyThreadState *tstate); +extern PyObject * _PyEval_GetFrameLocals(void); #ifdef __cplusplus diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 952a96009dda6c..efc19e33ec5dc5 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -234,6 +234,9 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame * frame); int _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg); +PyObject * +_PyFrame_GetLocals(_PyInterpreterFrame *frame, int include_hidden); + int _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame); diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index c2cf058c321fa5..9f28ced32bd26c 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -539,6 +539,28 @@ def b(): self._check_in_scopes(code, {"x": True, "y": ["b"]}, scopes=["function"]) self._check_in_scopes(code, raises=NameError, scopes=["class"]) + def test_iter_var_available_in_locals(self): + code = """ + l = [1, 2] + y = 0 + items = [locals()["x"] for x in l] + items2 = [vars()["x"] for x in l] + items3 = [("x" in dir()) for x in l] + items4 = [eval("x") for x in l] + # x is available, and does not overwrite y + [exec("y = x") for x in l] + """ + self._check_in_scopes( + code, + { + "items": [1, 2], + "items2": [1, 2], + "items3": [True, True], + "items4": [1, 2], + "y": 0 + } + ) + __test__ = {'doctests' : doctests} diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst new file mode 100644 index 00000000000000..f6d4fa8fc4d74e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-12-16-38-31.gh-issue-105340._jRHXe.rst @@ -0,0 +1,2 @@ +Include the comprehension iteration variable in ``locals()`` inside a +module- or class-scope comprehension. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 0158d72d6b4f98..18820551a0547e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1200,15 +1200,28 @@ frame_get_var(_PyInterpreterFrame *frame, PyCodeObject *co, int i, return 1; } -int -_PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) + +PyObject * +_PyFrame_GetLocals(_PyInterpreterFrame *frame, int include_hidden) { /* Merge fast locals into f->f_locals */ PyObject *locals = frame->f_locals; if (locals == NULL) { locals = frame->f_locals = PyDict_New(); if (locals == NULL) { - return -1; + return NULL; + } + } + PyObject *hidden = NULL; + + /* If include_hidden, "hidden" fast locals (from inlined comprehensions in + module/class scopes) will be included in the returned dict, but not in + frame->f_locals; the returned dict will be a modified copy. Non-hidden + locals will still be updated in frame->f_locals. */ + if (include_hidden) { + hidden = PyDict_New(); + if (hidden == NULL) { + return NULL; } } @@ -1224,6 +1237,11 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); if (kind & CO_FAST_HIDDEN) { + if (include_hidden && value != NULL) { + if (PyObject_SetItem(hidden, name, value) != 0) { + goto error; + } + } continue; } if (value == NULL) { @@ -1232,16 +1250,53 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) PyErr_Clear(); } else { - return -1; + goto error; } } } else { if (PyObject_SetItem(locals, name, value) != 0) { - return -1; + goto error; } } } + + if (include_hidden && PyDict_Size(hidden)) { + PyObject *innerlocals = PyDict_New(); + if (innerlocals == NULL) { + goto error; + } + if (PyDict_Merge(innerlocals, locals, 1) != 0) { + Py_DECREF(innerlocals); + goto error; + } + if (PyDict_Merge(innerlocals, hidden, 1) != 0) { + Py_DECREF(innerlocals); + goto error; + } + locals = innerlocals; + } + else { + Py_INCREF(locals); + } + Py_CLEAR(hidden); + + return locals; + + error: + Py_XDECREF(hidden); + return NULL; +} + + +int +_PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) +{ + PyObject *locals = _PyFrame_GetLocals(frame, 0); + if (locals == NULL) { + return -1; + } + Py_DECREF(locals); return 0; } diff --git a/Objects/object.c b/Objects/object.c index b20e87ef3fb23d..c27b13e9e0c31a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1690,13 +1690,15 @@ _dir_locals(void) PyObject *names; PyObject *locals; - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; names = PyMapping_Keys(locals); - if (!names) + Py_DECREF(locals); + if (!names) { return NULL; + } if (!PyList_Check(names)) { PyErr_Format(PyExc_TypeError, "dir(): expected keys() of locals to be a list, " @@ -1708,7 +1710,6 @@ _dir_locals(void) Py_DECREF(names); return NULL; } - /* the locals don't need to be DECREF'd */ return names; } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 9fe0067daa678c..49efafc07f4245 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -908,7 +908,7 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, PyObject *locals) /*[clinic end generated code: output=0a0824aa70093116 input=11ee718a8640e527]*/ { - PyObject *result, *source_copy; + PyObject *result = NULL, *source_copy; const char *str; if (locals != Py_None && !PyMapping_Check(locals)) { @@ -924,19 +924,25 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; } + else { + Py_INCREF(locals); + } } else if (locals == Py_None) - locals = globals; + locals = Py_NewRef(globals); + else { + Py_INCREF(locals); + } if (globals == NULL || locals == NULL) { PyErr_SetString(PyExc_TypeError, "eval must be given globals and locals " "when called without a frame"); - return NULL; + goto error; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); @@ -944,34 +950,38 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals, r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { - return NULL; + goto error; } if (PyCode_Check(source)) { if (PySys_Audit("exec", "O", source) < 0) { - return NULL; + goto error; } if (PyCode_GetNumFree((PyCodeObject *)source) > 0) { PyErr_SetString(PyExc_TypeError, "code object passed to eval() may not contain free variables"); - return NULL; + goto error; } - return PyEval_EvalCode(source, globals, locals); + result = PyEval_EvalCode(source, globals, locals); } + else { + PyCompilerFlags cf = _PyCompilerFlags_INIT; + cf.cf_flags = PyCF_SOURCE_IS_UTF8; + str = _Py_SourceAsString(source, "eval", "string, bytes or code", &cf, &source_copy); + if (str == NULL) + goto error; - PyCompilerFlags cf = _PyCompilerFlags_INIT; - cf.cf_flags = PyCF_SOURCE_IS_UTF8; - str = _Py_SourceAsString(source, "eval", "string, bytes or code", &cf, &source_copy); - if (str == NULL) - return NULL; + while (*str == ' ' || *str == '\t') + str++; - while (*str == ' ' || *str == '\t') - str++; + (void)PyEval_MergeCompilerFlags(&cf); + result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + Py_XDECREF(source_copy); + } - (void)PyEval_MergeCompilerFlags(&cf); - result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); - Py_XDECREF(source_copy); + error: + Py_XDECREF(locals); return result; } @@ -1006,36 +1016,43 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) { - locals = PyEval_GetLocals(); + locals = _PyEval_GetFrameLocals(); if (locals == NULL) return NULL; } + else { + Py_INCREF(locals); + } if (!globals || !locals) { PyErr_SetString(PyExc_SystemError, "globals and locals cannot be NULL"); return NULL; } } - else if (locals == Py_None) - locals = globals; + else if (locals == Py_None) { + locals = Py_NewRef(globals); + } + else { + Py_INCREF(locals); + } if (!PyDict_Check(globals)) { PyErr_Format(PyExc_TypeError, "exec() globals must be a dict, not %.100s", Py_TYPE(globals)->tp_name); - return NULL; + goto error; } if (!PyMapping_Check(locals)) { PyErr_Format(PyExc_TypeError, "locals must be a mapping or None, not %.100s", Py_TYPE(locals)->tp_name); - return NULL; + goto error; } int r = PyDict_Contains(globals, &_Py_ID(__builtins__)); if (r == 0) { r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins()); } if (r < 0) { - return NULL; + goto error; } if (closure == Py_None) { @@ -1048,7 +1065,7 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, if (closure) { PyErr_SetString(PyExc_TypeError, "cannot use a closure with this code object"); - return NULL; + goto error; } } else { int closure_is_ok = @@ -1068,12 +1085,12 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, PyErr_Format(PyExc_TypeError, "code object requires a closure of exactly length %zd", num_free); - return NULL; + goto error; } } if (PySys_Audit("exec", "O", source) < 0) { - return NULL; + goto error; } if (!closure) { @@ -1100,7 +1117,7 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, "string, bytes or code", &cf, &source_copy); if (str == NULL) - return NULL; + goto error; if (PyEval_MergeCompilerFlags(&cf)) v = PyRun_StringFlags(str, Py_file_input, globals, locals, &cf); @@ -1109,9 +1126,14 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, Py_XDECREF(source_copy); } if (v == NULL) - return NULL; + goto error; + Py_DECREF(locals); Py_DECREF(v); Py_RETURN_NONE; + + error: + Py_XDECREF(locals); + return NULL; } @@ -1721,10 +1743,7 @@ static PyObject * builtin_locals_impl(PyObject *module) /*[clinic end generated code: output=b46c94015ce11448 input=7874018d478d5c4b]*/ { - PyObject *d; - - d = PyEval_GetLocals(); - return Py_XNewRef(d); + return _PyEval_GetFrameLocals(); } @@ -2442,7 +2461,7 @@ builtin_vars_impl(PyObject *module, PyObject *object) PyObject *d; if (object == NULL) { - d = Py_XNewRef(PyEval_GetLocals()); + d = _PyEval_GetFrameLocals(); } else { if (_PyObject_LookupAttr(object, &_Py_ID(__dict__), &d) == 0) { diff --git a/Python/ceval.c b/Python/ceval.c index 9bcb83f9c993cf..6714229fd07846 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2261,6 +2261,19 @@ PyEval_GetLocals(void) return locals; } +PyObject * +_PyEval_GetFrameLocals(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate); + if (current_frame == NULL) { + _PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist"); + return NULL; + } + + return _PyFrame_GetLocals(current_frame, 1); +} + PyObject * PyEval_GetGlobals(void) { From 13aefd175e3c04529251f175c23cb3ed88451fd0 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Wed, 5 Jul 2023 18:12:21 -0600 Subject: [PATCH 284/446] gh-105256: What's New note for comprehension over locals() (#106378) --- Doc/whatsnew/3.12.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 1af80ea62b392d..a892f92dd26281 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -253,6 +253,12 @@ Inlining does result in a few visible behavior changes: * Calling :func:`locals` inside a comprehension now includes variables from outside the comprehension, and no longer includes the synthetic ``.0`` variable for the comprehension "argument". +* A comprehension iterating directly over ``locals()`` (e.g. ``[k for k in + locals()]``) may see "RuntimeError: dictionary changed size during iteration" + when run under tracing (e.g. code coverage measurement). This is the same + behavior already seen in e.g. ``for k in locals():``. To avoid the error, first + create a list of keys to iterate over: ``keys = list(locals()); [k for k in + keys]``. Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`. From 38aa89a52ed5194f70bbf07d699a2dd3720e2efd Mon Sep 17 00:00:00 2001 From: "C.A.M. Gerlach" Date: Thu, 6 Jul 2023 00:41:04 -0500 Subject: [PATCH 285/446] Doc: Add missing ref labels to exception groups/notes sections (#106465) --- Doc/library/exceptions.rst | 2 ++ Doc/tutorial/errors.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 9e1335436ee87f..4651eddf843700 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -871,6 +871,8 @@ The following exceptions are used as warning categories; see the .. versionadded:: 3.2 +.. _lib-exception-groups: + Exception groups ---------------- diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index ca5dc3314c63b6..6419ff621f1b31 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -578,6 +578,8 @@ the following pattern:: ... +.. _tut-exception-notes: + Enriching Exceptions with Notes =============================== From 99b00efd5edfd5b26bf9e2a35cbfc96277fdcbb1 Mon Sep 17 00:00:00 2001 From: Ariel Eizenberg Date: Thu, 6 Jul 2023 10:02:22 +0300 Subject: [PATCH 286/446] gh-106238: Handle KeyboardInterrupt during logging._acquireLock() (GH-106239) Co-authored-by: Ariel Eizenberg --- Lib/logging/__init__.py | 6 +++++- .../Library/2023-06-29-12-40-52.gh-issue-106238.VulKb9.rst | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-29-12-40-52.gh-issue-106238.VulKb9.rst diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index ba2ed44b095071..fe2039af0334a0 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -238,7 +238,11 @@ def _acquireLock(): This should be released with _releaseLock(). """ if _lock: - _lock.acquire() + try: + _lock.acquire() + except BaseException: + _lock.release() + raise def _releaseLock(): """ diff --git a/Misc/NEWS.d/next/Library/2023-06-29-12-40-52.gh-issue-106238.VulKb9.rst b/Misc/NEWS.d/next/Library/2023-06-29-12-40-52.gh-issue-106238.VulKb9.rst new file mode 100644 index 00000000000000..52e78382fd618e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-29-12-40-52.gh-issue-106238.VulKb9.rst @@ -0,0 +1 @@ +Fix rare concurrency bug in lock acquisition by the logging package. From d0c6ba956fca28785ad4dea6423cd44fd1124cad Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 6 Jul 2023 14:23:02 +0100 Subject: [PATCH 287/446] gh-104683: clinic.py: Don't needlessly reimplement `contextlib.redirect_stdout` (#106478) clinic.py: Don't needlessly reimplement `contextlib.redirect_stdout` --- Tools/clinic/clinic.py | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 7ada7e9d917b38..306dca8d44dd2f 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1617,19 +1617,6 @@ def render_function( return clinic.get_destination('block').dump() - - -@contextlib.contextmanager -def OverrideStdioWith(stdout): - saved_stdout = sys.stdout - sys.stdout = stdout - try: - yield - finally: - assert sys.stdout is stdout - sys.stdout = saved_stdout - - def create_regex( before: str, after: str, @@ -2331,17 +2318,14 @@ def compute_checksum( return s - - class PythonParser: def __init__(self, clinic: Clinic) -> None: pass def parse(self, block: Block) -> None: - s = io.StringIO() - with OverrideStdioWith(s): + with contextlib.redirect_stdout(io.StringIO()) as s: exec(block.input) - block.output = s.getvalue() + block.output = s.getvalue() class Module: From e7cd55753b00d6f7e5c8998bae73ebaa9e86398d Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Thu, 6 Jul 2023 17:06:18 +0200 Subject: [PATCH 288/446] Introduce a gate/check GHA job (#97533) Co-authored-by: Hugo van Kemenade --- .github/workflows/build.yml | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34fcce445d0cd4..06551b13219c2a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -519,3 +519,60 @@ jobs: run: make pythoninfo - name: Tests run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu" + + all-required-green: # This job does nothing and is only used for the branch protection + name: All required checks pass + if: always() + + needs: + - check_source # Transitive dependency, needed to access `run_tests` value + - check-docs + - check_generated_files + - build_win32 + - build_win_amd64 + - build_macos + - build_ubuntu + - build_ubuntu_ssltests + - test_hypothesis + - build_asan + + runs-on: ubuntu-latest + + steps: + - name: Check whether the needed jobs succeeded or failed + uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe + with: + allowed-failures: >- + build_macos, + build_ubuntu_ssltests, + build_win32, + test_hypothesis, + allowed-skips: >- + ${{ + !fromJSON(needs.check_source.outputs.run-docs) + && ' + check-docs, + ' + || '' + }} + ${{ + needs.check_source.outputs.run_tests != 'true' + && ' + check_generated_files, + build_win32, + build_win_amd64, + build_macos, + build_ubuntu, + build_ubuntu_ssltests, + build_asan, + ' + || '' + }} + ${{ + !fromJSON(needs.check_source.outputs.run_hypothesis) + && ' + test_hypothesis, + ' + || '' + }} + jobs: ${{ toJSON(needs) }} From 56353b10023ff12c7c8d6288ae4bf7bdcd5d4b6c Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Thu, 6 Jul 2023 19:54:45 +0200 Subject: [PATCH 289/446] gh-106458: Mark `testthreadingmock.py` with `@requires_working_threading` (GH-106366) Mark `testthreadingmock.py` with `threading_helper.requires_working_threading`. Also add longer delays to reduce the change of a race conditions on the tests that validate short timeouts. --- .../testmock/testthreadingmock.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py index 2b4dca3a4be179..c6f179490d01f8 100644 --- a/Lib/test/test_unittest/testmock/testthreadingmock.py +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -2,9 +2,13 @@ import unittest import concurrent.futures +from test.support import threading_helper from unittest.mock import patch, ThreadingMock, call +threading_helper.requires_working_threading(module=True) + + class Something: def method_1(self): pass @@ -133,11 +137,9 @@ def test_wait_failed_with_timeout_override(self): with patch(f"{__name__}.Something", waitable_mock): something = Something() - self.run_async(something.method_1, delay=0.1) + self.run_async(something.method_1, delay=0.5) with self.assertRaises(AssertionError): something.method_1.wait_until_called(timeout=0.05) - with self.assertRaises(AssertionError): - something.method_1.wait_until_any_call_with(timeout=0.05) def test_wait_success_called_before(self): waitable_mock = self._make_mock() @@ -163,10 +165,10 @@ def test_wait_until_any_call_with_positional(self): with patch(f"{__name__}.Something", waitable_mock): something = Something() - self.run_async(something.method_1, 1, delay=0.1) - self.run_async(something.method_1, 2, delay=0.2) - self.run_async(something.method_1, 3, delay=0.3) + self.run_async(something.method_1, 1, delay=0.2) self.assertNotIn(call(1), something.method_1.mock_calls) + self.run_async(something.method_1, 2, delay=0.5) + self.run_async(something.method_1, 3, delay=0.6) something.method_1.wait_until_any_call_with(1) something.method_1.assert_called_with(1) @@ -182,10 +184,10 @@ def test_wait_until_any_call_with_keywords(self): with patch(f"{__name__}.Something", waitable_mock): something = Something() - self.run_async(something.method_1, a=1, delay=0.1) - self.run_async(something.method_1, b=2, delay=0.2) - self.run_async(something.method_1, c=3, delay=0.3) + self.run_async(something.method_1, a=1, delay=0.2) self.assertNotIn(call(a=1), something.method_1.mock_calls) + self.run_async(something.method_1, b=2, delay=0.5) + self.run_async(something.method_1, c=3, delay=0.6) something.method_1.wait_until_any_call_with(a=1) something.method_1.assert_called_with(a=1) From 003ba71dcbe94f0d5cb1d0c56d7f1d5a6dae56f7 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 6 Jul 2023 11:39:53 -0700 Subject: [PATCH 290/446] gh-104584: Fix error handling from backedge optimization (#106484) When `_PyOptimizer_BackEdge` returns `NULL`, we should restore `next_instr` (and `stack_pointer`). To accomplish this we should jump to `resume_with_error` instead of just `error`. The problem this causes is subtle -- the only repro I have is in PR gh-106393, at commit d7df54b139bcc47f5ea094bfaa9824f79bc45adc. But the fix is real (as shown later in that PR). While we're at it, also improve the debug output: the offsets at which traces are identified are now measured in bytes, and always show the start offset. This makes it easier to correlate executor calls with optimizer calls, and either with `dis` output. * Issue: gh-104584 --- Python/bytecodes.c | 2 +- Python/ceval.c | 4 ++-- Python/generated_cases.c.h | 2 +- Python/optimizer.c | 18 +++++++++++------- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f69ac2beef4c20..70b52391e6bdaa 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2234,7 +2234,7 @@ dummy_func( frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; - goto error; + goto resume_with_error; } assert(frame == cframe.current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); diff --git a/Python/ceval.c b/Python/ceval.c index 6714229fd07846..0ee95bc3a3a4bb 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2737,11 +2737,11 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject #endif DPRINTF(3, - "Entering _PyUopExecute for %s (%s:%d) at offset %ld\n", + "Entering _PyUopExecute for %s (%s:%d) at byte offset %ld\n", PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname), PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename), _PyFrame_GetCode(frame)->co_firstlineno, - (long)(frame->prev_instr + 1 - + 2 * (long)(frame->prev_instr + 1 - (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive)); PyThreadState *tstate = _PyThreadState_GET(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index eb2422943984b1..6000ab2da11330 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3193,7 +3193,7 @@ frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); if (frame == NULL) { frame = cframe.current_frame; - goto error; + goto resume_with_error; } assert(frame == cframe.current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1); diff --git a/Python/optimizer.c b/Python/optimizer.c index c3ab649b51b0eb..2c1be61f8d614e 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -181,6 +181,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI } insert_executor(code, src, index, executor); assert(frame->prev_instr == src); + frame->prev_instr = dest - 1; return executor->execute(executor, frame, stack_pointer); jump_to_destination: frame->prev_instr = dest - 1; @@ -201,7 +202,7 @@ PyUnstable_GetExecutor(PyCodeObject *code, int offset) } i += _PyInstruction_GetLength(code, i); } - PyErr_SetString(PyExc_ValueError, "no executor at given offset"); + PyErr_SetString(PyExc_ValueError, "no executor at given byte offset"); return NULL; } @@ -373,6 +374,9 @@ translate_bytecode_to_trace( _PyUOpInstruction *trace, int max_length) { +#ifdef Py_DEBUG + _Py_CODEUNIT *initial_instr = instr; +#endif int trace_length = 0; #ifdef Py_DEBUG @@ -398,11 +402,11 @@ translate_bytecode_to_trace( trace_length++; DPRINTF(4, - "Optimizing %s (%s:%d) at offset %ld\n", + "Optimizing %s (%s:%d) at byte offset %ld\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive)); for (;;) { ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); @@ -492,21 +496,21 @@ translate_bytecode_to_trace( if (trace_length > 3) { ADD_TO_TRACE(EXIT_TRACE, 0); DPRINTF(1, - "Created a trace for %s (%s:%d) at offset %ld -- length %d\n", + "Created a trace for %s (%s:%d) at byte offset %ld -- length %d\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive), + 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive), trace_length); return trace_length; } else { DPRINTF(4, - "No trace for %s (%s:%d) at offset %ld\n", + "No trace for %s (%s:%d) at byte offset %ld\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - (long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive)); } return 0; From 5548097925b9924ebf761376d632c5198d01ebd5 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 6 Jul 2023 22:17:12 +0100 Subject: [PATCH 291/446] gh-104683: clinic.py: refactor four simple classes as dataclasses (#106476) --- Tools/clinic/clinic.py | 51 +++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 306dca8d44dd2f..24d6255f262da4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -13,6 +13,7 @@ import contextlib import copy import cpp +import dataclasses as dc import enum import functools import hashlib @@ -1858,11 +1859,10 @@ def is_stop_line(line): return Block(input_output(), dsl_name, output=output) +@dc.dataclass(slots=True) class BlockPrinter: - - def __init__(self, language, f=None): - self.language = language - self.f = f or io.StringIO() + language: Language + f: io.StringIO = dc.field(default_factory=io.StringIO) def print_block(self, block, *, core_includes=False): input = block.input @@ -2328,15 +2328,13 @@ def parse(self, block: Block) -> None: block.output = s.getvalue() +@dc.dataclass(repr=False) class Module: - def __init__( - self, - name: str, - module = None - ) -> None: - self.name = name - self.module = self.parent = module + name: str + module: Module | None = None + def __post_init__(self) -> None: + self.parent = self.module self.modules: ModuleDict = {} self.classes: ClassDict = {} self.functions: list[Function] = [] @@ -2345,22 +2343,16 @@ def __repr__(self) -> str: return "" +@dc.dataclass(repr=False) class Class: - def __init__( - self, - name: str, - module: Module | None = None, - cls = None, - typedef: str | None = None, - type_object: str | None = None - ) -> None: - self.name = name - self.module = module - self.cls = cls - self.typedef = typedef - self.type_object = type_object - self.parent = cls or module - + name: str + module: Module | None = None + cls: Class | None = None + typedef: str | None = None + type_object: str | None = None + + def __post_init__(self) -> None: + self.parent = self.cls or self.module self.classes: ClassDict = {} self.functions: list[Function] = [] @@ -2606,13 +2598,10 @@ def get_displayname(self, i: int) -> str: return f'"argument {i}"' +@dc.dataclass class LandMine: # try to access any - def __init__(self, message: str) -> None: - self.__message__ = message - - def __repr__(self) -> str: - return '" + __message__: str def __getattribute__(self, name: str): if name in ('__repr__', '__message__'): From 67a798888dcde13bbb1e17cfcc3c742c94e67a07 Mon Sep 17 00:00:00 2001 From: Dustin Rodrigues Date: Thu, 6 Jul 2023 18:34:00 -0400 Subject: [PATCH 292/446] closes gh-106479: fix typo in __cplusplus macro (gh-106480) --- Lib/test/_testcppext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/_testcppext.cpp b/Lib/test/_testcppext.cpp index 0e381a78c5ceed..82b471312dd2b9 100644 --- a/Lib/test/_testcppext.cpp +++ b/Lib/test/_testcppext.cpp @@ -86,7 +86,7 @@ test_api_casts(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) // gh-93442: Pass 0 as NULL for PyObject* Py_XINCREF(0); Py_XDECREF(0); -#if _cplusplus >= 201103 +#if __cplusplus >= 201103 // Test nullptr passed as PyObject* Py_XINCREF(nullptr); Py_XDECREF(nullptr); From 76fac7bce55302a8e9a524d72f5384fd89e6dfde Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 6 Jul 2023 15:45:56 -0700 Subject: [PATCH 293/446] gh-104584: Clean up and fix uops tests and fix crash (#106492) The uops test wasn't testing anything by default, and was failing when run with -Xuops. Made the two executor-related context managers global, so TestUops can use them (notably `with temporary_optimizer(opt)`). Made clear_executor() a little more thorough. Fixed a crash upon finalizing a uop optimizer, by adding a `tp_dealloc` handler. --- Lib/test/test_capi/test_misc.py | 54 ++++++++++++++++++--------------- Python/optimizer.c | 10 ++++-- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index de9f00a9e5fb48..8d597e79902557 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2343,23 +2343,26 @@ def func(): names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"] self.do_test(func, names) -class TestOptimizerAPI(unittest.TestCase): - @contextlib.contextmanager - def temporary_optimizer(self, opt): - _testinternalcapi.set_optimizer(opt) - try: - yield - finally: - _testinternalcapi.set_optimizer(None) +@contextlib.contextmanager +def temporary_optimizer(opt): + _testinternalcapi.set_optimizer(opt) + try: + yield + finally: + _testinternalcapi.set_optimizer(None) - @contextlib.contextmanager - def clear_executors(self, func): - try: - yield - finally: - #Clear executors - func.__code__ = func.__code__.replace() +@contextlib.contextmanager +def clear_executors(func): + # Clear executors in func before and after running a block + func.__code__ = func.__code__.replace() + try: + yield + finally: + func.__code__ = func.__code__.replace() + + +class TestOptimizerAPI(unittest.TestCase): def test_get_set_optimizer(self): self.assertEqual(_testinternalcapi.get_optimizer(), None) @@ -2381,9 +2384,9 @@ def loop(): for repeat in range(5): opt = _testinternalcapi.get_counter_optimizer() - with self.temporary_optimizer(opt): + with temporary_optimizer(opt): self.assertEqual(opt.get_count(), 0) - with self.clear_executors(loop): + with clear_executors(loop): loop() self.assertEqual(opt.get_count(), 1000) @@ -2409,7 +2412,7 @@ def long_loop(): long_loop = ns['long_loop'] opt = _testinternalcapi.get_counter_optimizer() - with self.temporary_optimizer(opt): + with temporary_optimizer(opt): self.assertEqual(opt.get_count(), 0) long_loop() self.assertEqual(opt.get_count(), 10) @@ -2418,24 +2421,27 @@ def long_loop(): class TestUops(unittest.TestCase): def test_basic_loop(self): - def testfunc(x): i = 0 while i < x: i += 1 - testfunc(1000) + opt = _testinternalcapi.get_uop_optimizer() + + with temporary_optimizer(opt): + testfunc(1000) ex = None - for offset in range(0, 100, 2): + for offset in range(0, len(testfunc.__code__.co_code), 2): try: ex = _testinternalcapi.get_executor(testfunc.__code__, offset) break except ValueError: pass - if ex is None: - return - self.assertIn("SAVE_IP", str(ex)) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("SAVE_IP", uops) + self.assertIn("LOAD_FAST", uops) if __name__ == "__main__": diff --git a/Python/optimizer.c b/Python/optimizer.c index 2c1be61f8d614e..d2fdca59fe46c8 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -532,7 +532,7 @@ uop_optimize( return trace_length; } OBJECT_STAT_INC(optimization_traces_created); - _PyUOpExecutorObject *executor = (_PyUOpExecutorObject *)_PyObject_New(&UOpExecutor_Type); + _PyUOpExecutorObject *executor = PyObject_New(_PyUOpExecutorObject, &UOpExecutor_Type); if (executor == NULL) { return -1; } @@ -542,18 +542,24 @@ uop_optimize( return 1; } +static void +uop_opt_dealloc(PyObject *self) { + PyObject_Free(self); +} + static PyTypeObject UOpOptimizer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "uop_optimizer", .tp_basicsize = sizeof(_PyOptimizerObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_dealloc = uop_opt_dealloc, }; PyObject * PyUnstable_Optimizer_NewUOpOptimizer(void) { - _PyOptimizerObject *opt = (_PyOptimizerObject *)_PyObject_New(&UOpOptimizer_Type); + _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &UOpOptimizer_Type); if (opt == NULL) { return NULL; } From c60df361ce2d734148d503f4a711e67c110fe223 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 6 Jul 2023 15:46:50 -0700 Subject: [PATCH 294/446] gh-90876: Restore the ability to import multiprocessing when `sys.executable` is `None` (#106464) Prevent `multiprocessing.spawn` from failing to *import* in environments where `sys.executable` is `None`. This regressed in 3.11 with the addition of support for path-like objects in multiprocessing. Adds a test decorator to have tests only run when part of test_multiprocessing_spawn to `_test_multiprocessing.py` so we can start to avoid re-running the same not-global-state specific test in all 3 modes when there is no need. --- Lib/multiprocessing/spawn.py | 6 +- Lib/test/_test_multiprocessing.py | 82 +++++++++++++++++-- ...3-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst | 3 + 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index 09f8a229d7cccb..f1af7709104714 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -31,11 +31,13 @@ WINSERVICE = False else: WINEXE = getattr(sys, 'frozen', False) - WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") + WINSERVICE = sys.executable and sys.executable.lower().endswith("pythonservice.exe") def set_executable(exe): global _python_exe - if sys.platform == 'win32': + if exe is None: + _python_exe = exe + elif sys.platform == 'win32': _python_exe = os.fsdecode(exe) else: _python_exe = os.fsencode(exe) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c101fe980ceed5..c1f9487ae80511 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -13,6 +13,7 @@ import os import gc import errno +import functools import signal import array import socket @@ -31,6 +32,7 @@ from test.support import hashlib_helper from test.support import import_helper from test.support import os_helper +from test.support import script_helper from test.support import socket_helper from test.support import threading_helper from test.support import warnings_helper @@ -171,6 +173,59 @@ def check_enough_semaphores(): "to run the test (required: %d)." % nsems_min) +def only_run_in_spawn_testsuite(reason): + """Returns a decorator: raises SkipTest when SM != spawn at test time. + + This can be useful to save overall Python test suite execution time. + "spawn" is the universal mode available on all platforms so this limits the + decorated test to only execute within test_multiprocessing_spawn. + + This would not be necessary if we refactored our test suite to split things + into other test files when they are not start method specific to be rerun + under all start methods. + """ + + def decorator(test_item): + + @functools.wraps(test_item) + def spawn_check_wrapper(*args, **kwargs): + if (start_method := multiprocessing.get_start_method()) != "spawn": + raise unittest.SkipTest(f"{start_method=}, not 'spawn'; {reason}") + return test_item(*args, **kwargs) + + return spawn_check_wrapper + + return decorator + + +class TestInternalDecorators(unittest.TestCase): + """Logic within a test suite that could errantly skip tests? Test it!""" + + @unittest.skipIf(sys.platform == "win32", "test requires that fork exists.") + def test_only_run_in_spawn_testsuite(self): + if multiprocessing.get_start_method() != "spawn": + raise unittest.SkipTest("only run in test_multiprocessing_spawn.") + + try: + @only_run_in_spawn_testsuite("testing this decorator") + def return_four_if_spawn(): + return 4 + except Exception as err: + self.fail(f"expected decorated `def` not to raise; caught {err}") + + orig_start_method = multiprocessing.get_start_method(allow_none=True) + try: + multiprocessing.set_start_method("spawn", force=True) + self.assertEqual(return_four_if_spawn(), 4) + multiprocessing.set_start_method("fork", force=True) + with self.assertRaises(unittest.SkipTest) as ctx: + return_four_if_spawn() + self.assertIn("testing this decorator", str(ctx.exception)) + self.assertIn("start_method=", str(ctx.exception)) + finally: + multiprocessing.set_start_method(orig_start_method, force=True) + + # # Creates a wrapper for a function which records the time it takes to finish # @@ -5815,6 +5870,7 @@ def test_namespace(self): class TestNamedResource(unittest.TestCase): + @only_run_in_spawn_testsuite("spawn specific test.") def test_global_named_resource_spawn(self): # # gh-90549: Check that global named resources in main module @@ -5825,22 +5881,18 @@ def test_global_named_resource_spawn(self): with open(testfn, 'w', encoding='utf-8') as f: f.write(textwrap.dedent('''\ import multiprocessing as mp - ctx = mp.get_context('spawn') - global_resource = ctx.Semaphore() - def submain(): pass - if __name__ == '__main__': p = ctx.Process(target=submain) p.start() p.join() ''')) - rc, out, err = test.support.script_helper.assert_python_ok(testfn) + rc, out, err = script_helper.assert_python_ok(testfn) # on error, err = 'UserWarning: resource_tracker: There appear to # be 1 leaked semaphore objects to clean up at shutdown' - self.assertEqual(err, b'') + self.assertFalse(err, msg=err.decode('utf-8')) class MiscTestCase(unittest.TestCase): @@ -5849,6 +5901,24 @@ def test__all__(self): support.check__all__(self, multiprocessing, extra=multiprocessing.__all__, not_exported=['SUBDEBUG', 'SUBWARNING']) + @only_run_in_spawn_testsuite("avoids redundant testing.") + def test_spawn_sys_executable_none_allows_import(self): + # Regression test for a bug introduced in + # https://github.com/python/cpython/issues/90876 that caused an + # ImportError in multiprocessing when sys.executable was None. + # This can be true in embedded environments. + rc, out, err = script_helper.assert_python_ok( + "-c", + """if 1: + import sys + sys.executable = None + assert "multiprocessing" not in sys.modules, "already imported!" + import multiprocessing + import multiprocessing.spawn # This should not fail\n""", + ) + self.assertEqual(rc, 0) + self.assertFalse(err, msg=err.decode('utf-8')) + # # Mixins diff --git a/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst new file mode 100644 index 00000000000000..3e062b5add6d89 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst @@ -0,0 +1,3 @@ +Prevent :mod:`multiprocessing.spawn` from failing to *import* in environments +where ``sys.executable`` is ``None``. This regressed in 3.11 with the addition +of support for path-like objects in multiprocessing. From e1d45b8ed43e1590862319fec33539f8adbc0849 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 6 Jul 2023 16:46:06 -0700 Subject: [PATCH 295/446] gh-104584: Handle EXTENDED_ARG in superblock creation (#106489) With test. --- Lib/test/test_capi/test_misc.py | 56 +++++++++++++++++++++++++++++++++ Python/optimizer.c | 16 ++++++++++ 2 files changed, 72 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 8d597e79902557..181e6b8077f9f5 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -7,6 +7,7 @@ import importlib.machinery import importlib.util import json +import opcode import os import pickle import queue @@ -2352,6 +2353,7 @@ def temporary_optimizer(opt): finally: _testinternalcapi.set_optimizer(None) + @contextlib.contextmanager def clear_executors(func): # Clear executors in func before and after running a block @@ -2418,6 +2420,19 @@ def long_loop(): self.assertEqual(opt.get_count(), 10) + +def get_first_executor(code): + co_code = code.co_code + JUMP_BACKWARD = opcode.opmap["JUMP_BACKWARD"] + for i in range(0, len(co_code), 2): + if co_code[i] == JUMP_BACKWARD or 1: + try: + return _testinternalcapi.get_executor(code, i) + except ValueError: + pass + return None + + class TestUops(unittest.TestCase): def test_basic_loop(self): @@ -2443,6 +2458,47 @@ def testfunc(x): self.assertIn("SAVE_IP", uops) self.assertIn("LOAD_FAST", uops) + def test_extended_arg(self): + "Check EXTENDED_ARG handling in superblock creation" + def many_vars(): + # 260 vars, so z9 should have index 259 + a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 42 + b0 = b1 = b2 = b3 = b4 = b5 = b6 = b7 = b8 = b9 = 42 + c0 = c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = c9 = 42 + d0 = d1 = d2 = d3 = d4 = d5 = d6 = d7 = d8 = d9 = 42 + e0 = e1 = e2 = e3 = e4 = e5 = e6 = e7 = e8 = e9 = 42 + f0 = f1 = f2 = f3 = f4 = f5 = f6 = f7 = f8 = f9 = 42 + g0 = g1 = g2 = g3 = g4 = g5 = g6 = g7 = g8 = g9 = 42 + h0 = h1 = h2 = h3 = h4 = h5 = h6 = h7 = h8 = h9 = 42 + i0 = i1 = i2 = i3 = i4 = i5 = i6 = i7 = i8 = i9 = 42 + j0 = j1 = j2 = j3 = j4 = j5 = j6 = j7 = j8 = j9 = 42 + k0 = k1 = k2 = k3 = k4 = k5 = k6 = k7 = k8 = k9 = 42 + l0 = l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = 42 + m0 = m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = 42 + n0 = n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = n9 = 42 + o0 = o1 = o2 = o3 = o4 = o5 = o6 = o7 = o8 = o9 = 42 + p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = p9 = 42 + q0 = q1 = q2 = q3 = q4 = q5 = q6 = q7 = q8 = q9 = 42 + r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = 42 + s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = 42 + t0 = t1 = t2 = t3 = t4 = t5 = t6 = t7 = t8 = t9 = 42 + u0 = u1 = u2 = u3 = u4 = u5 = u6 = u7 = u8 = u9 = 42 + v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v9 = 42 + w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = w8 = w9 = 42 + x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = x8 = x9 = 42 + y0 = y1 = y2 = y3 = y4 = y5 = y6 = y7 = y8 = y9 = 42 + z0 = z1 = z2 = z3 = z4 = z5 = z6 = z7 = z8 = z9 = 42 + while z9 > 0: + z9 = z9 - 1 + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + ex = get_first_executor(many_vars.__code__) + self.assertIsNone(ex) + many_vars() + ex = get_first_executor(many_vars.__code__) + self.assertIn(("LOAD_FAST", 259), list(ex)) + if __name__ == "__main__": unittest.main() diff --git a/Python/optimizer.c b/Python/optimizer.c index d2fdca59fe46c8..db117bb180c1c8 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -412,6 +412,13 @@ translate_bytecode_to_trace( ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); int opcode = instr->op.code; uint64_t operand = instr->op.arg; + int extras = 0; + while (opcode == EXTENDED_ARG) { + instr++; + extras += 1; + opcode = instr->op.code; + operand = (operand << 8) | instr->op.arg; + } switch (opcode) { case LOAD_FAST_LOAD_FAST: case STORE_FAST_LOAD_FAST: @@ -458,6 +465,15 @@ translate_bytecode_to_trace( int offset = expansion->uops[i].offset; switch (expansion->uops[i].size) { case 0: + if (extras && OPCODE_HAS_JUMP(opcode)) { + if (opcode == JUMP_BACKWARD_NO_INTERRUPT) { + operand -= extras; + } + else { + assert(opcode != JUMP_BACKWARD); + operand += extras; + } + } break; case 1: operand = read_u16(&instr[offset].cache); From 24fb627ea7a4d57cf479b7516bafdb6c253a1645 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 7 Jul 2023 11:09:26 +0100 Subject: [PATCH 296/446] GH-106057: Handle recursion errors in inline class calls properly. (GH-106108) --- Lib/test/test_class.py | 15 ++++ Python/bytecodes.c | 7 +- Python/executor_cases.c.h | 20 ++--- Python/generated_cases.c.h | 157 +++++++++++++++++++------------------ 4 files changed, 108 insertions(+), 91 deletions(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index d7a48e55b10180..894e0ca67deabc 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -740,6 +740,21 @@ class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass class A(0, *range(1, 8), **d, foo='bar'): pass self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'})) + def testClassCallRecursionLimit(self): + class C: + def __init__(self): + self.c = C() + + with self.assertRaises(RecursionError): + C() + + def add_one_level(): + #Each call to C() consumes 2 levels, so offset by 1. + C() + + with self.assertRaises(RecursionError): + add_one_level() + if __name__ == '__main__': unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 70b52391e6bdaa..89b077ac428345 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2985,9 +2985,6 @@ dummy_func( goto error; } Py_DECREF(tp); - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); @@ -3011,6 +3008,10 @@ dummy_func( shim->previous = frame; frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); + /* Account for pushing the extra frame. + * We don't check recursion depth here, + * as it will be checked after start_frame */ + tstate->py_recursion_remaining--; goto start_frame; } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 39a4490e51c24a..29ebb0b3e8b2d9 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1811,7 +1811,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3018 "Python/bytecodes.c" + #line 3019 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1827,7 +1827,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3432 "Python/bytecodes.c" + #line 3433 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1847,7 +1847,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3446 "Python/bytecodes.c" + #line 3447 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1883,13 +1883,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3496 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 1889 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3498 "Python/bytecodes.c" + #line 3499 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 1895 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -1901,7 +1901,7 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3502 "Python/bytecodes.c" + #line 3503 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -1916,7 +1916,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3511 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1936,7 +1936,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3524 "Python/bytecodes.c" + #line 3525 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -1950,7 +1950,7 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3531 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 1957 "Python/executor_cases.c.h" @@ -1962,7 +1962,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3556 "Python/bytecodes.c" + #line 3557 "Python/bytecodes.c" assert(oparg >= 2); #line 1968 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6000ab2da11330..eb8b50e5c905d4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4147,9 +4147,6 @@ goto error; } Py_DECREF(tp); - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); @@ -4173,13 +4170,17 @@ shim->previous = frame; frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); + /* Account for pushing the extra frame. + * We don't check recursion depth here, + * as it will be checked after start_frame */ + tstate->py_recursion_remaining--; goto start_frame; - #line 4178 "Python/generated_cases.c.h" + #line 4179 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3018 "Python/bytecodes.c" + #line 3019 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4187,7 +4188,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4191 "Python/generated_cases.c.h" + #line 4192 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4197,7 +4198,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3028 "Python/bytecodes.c" + #line 3029 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4219,7 +4220,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4223 "Python/generated_cases.c.h" + #line 4224 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4233,7 +4234,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3053 "Python/bytecodes.c" + #line 3054 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4261,7 +4262,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4265 "Python/generated_cases.c.h" + #line 4266 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4275,7 +4276,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3084 "Python/bytecodes.c" + #line 3085 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4307,7 +4308,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4311 "Python/generated_cases.c.h" + #line 4312 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4321,7 +4322,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3119 "Python/bytecodes.c" + #line 3120 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4353,7 +4354,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4357 "Python/generated_cases.c.h" + #line 4358 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4367,7 +4368,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3154 "Python/bytecodes.c" + #line 3155 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4392,7 +4393,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4396 "Python/generated_cases.c.h" + #line 4397 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4405,7 +4406,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3181 "Python/bytecodes.c" + #line 3182 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4432,7 +4433,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4436 "Python/generated_cases.c.h" + #line 4437 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4444,7 +4445,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3211 "Python/bytecodes.c" + #line 3212 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4462,14 +4463,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4466 "Python/generated_cases.c.h" + #line 4467 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3231 "Python/bytecodes.c" + #line 3232 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4500,7 +4501,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4504 "Python/generated_cases.c.h" + #line 4505 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4513,7 +4514,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3265 "Python/bytecodes.c" + #line 3266 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4542,7 +4543,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4546 "Python/generated_cases.c.h" + #line 4547 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4555,7 +4556,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3297 "Python/bytecodes.c" + #line 3298 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4584,7 +4585,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4588 "Python/generated_cases.c.h" + #line 4589 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4597,7 +4598,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3329 "Python/bytecodes.c" + #line 3330 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4625,7 +4626,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4629 "Python/generated_cases.c.h" + #line 4630 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4635,9 +4636,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3360 "Python/bytecodes.c" + #line 3361 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4641 "Python/generated_cases.c.h" + #line 4642 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4646,7 +4647,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3364 "Python/bytecodes.c" + #line 3365 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4708,14 +4709,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4712 "Python/generated_cases.c.h" + #line 4713 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3426 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4719 "Python/generated_cases.c.h" + #line 4720 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4726,7 +4727,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3432 "Python/bytecodes.c" + #line 3433 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4738,7 +4739,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4742 "Python/generated_cases.c.h" + #line 4743 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4746,7 +4747,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3446 "Python/bytecodes.c" + #line 3447 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4771,14 +4772,14 @@ default: Py_UNREACHABLE(); } - #line 4775 "Python/generated_cases.c.h" + #line 4776 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3473 "Python/bytecodes.c" + #line 3474 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4799,7 +4800,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4803 "Python/generated_cases.c.h" + #line 4804 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4807,15 +4808,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3496 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4813 "Python/generated_cases.c.h" + #line 4814 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3498 "Python/bytecodes.c" + #line 3499 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4819 "Python/generated_cases.c.h" + #line 4820 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4825,14 +4826,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3502 "Python/bytecodes.c" + #line 3503 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4836 "Python/generated_cases.c.h" + #line 4837 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4840,7 +4841,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3511 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4851,7 +4852,7 @@ else { res = value; } - #line 4855 "Python/generated_cases.c.h" + #line 4856 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4860,12 +4861,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3524 "Python/bytecodes.c" + #line 3525 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4869 "Python/generated_cases.c.h" + #line 4870 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4874,10 +4875,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3531 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4881 "Python/generated_cases.c.h" + #line 4882 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4889,7 +4890,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3536 "Python/bytecodes.c" + #line 3537 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4904,12 +4905,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4908 "Python/generated_cases.c.h" + #line 4909 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3551 "Python/bytecodes.c" + #line 3552 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4913 "Python/generated_cases.c.h" + #line 4914 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4919,16 +4920,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3556 "Python/bytecodes.c" + #line 3557 "Python/bytecodes.c" assert(oparg >= 2); - #line 4925 "Python/generated_cases.c.h" + #line 4926 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3560 "Python/bytecodes.c" + #line 3561 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4940,48 +4941,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4944 "Python/generated_cases.c.h" + #line 4945 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3574 "Python/bytecodes.c" + #line 3575 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4950 "Python/generated_cases.c.h" + #line 4951 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3578 "Python/bytecodes.c" + #line 3579 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4958 "Python/generated_cases.c.h" + #line 4959 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3583 "Python/bytecodes.c" + #line 3584 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4969 "Python/generated_cases.c.h" + #line 4970 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3591 "Python/bytecodes.c" + #line 3592 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4980 "Python/generated_cases.c.h" + #line 4981 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3599 "Python/bytecodes.c" + #line 3600 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4993,12 +4994,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4997 "Python/generated_cases.c.h" + #line 4998 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3613 "Python/bytecodes.c" + #line 3614 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5010,30 +5011,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5014 "Python/generated_cases.c.h" + #line 5015 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3627 "Python/bytecodes.c" + #line 3628 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5025 "Python/generated_cases.c.h" + #line 5026 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3635 "Python/bytecodes.c" + #line 3636 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5032 "Python/generated_cases.c.h" + #line 5033 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3640 "Python/bytecodes.c" + #line 3641 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5039 "Python/generated_cases.c.h" + #line 5040 "Python/generated_cases.c.h" } From 3e5ce7968f5ab715f649e296e1f6b499621b8091 Mon Sep 17 00:00:00 2001 From: Andrew Geng Date: Fri, 7 Jul 2023 07:41:54 -0400 Subject: [PATCH 297/446] gh-106503: asyncio._SelectorSocketTransport: fix cyclic reference on close(). (#106504) --- Lib/asyncio/selector_events.py | 1 + Misc/ACKS | 1 + .../next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index fa2422b7fba4a7..f895750e3cf959 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1202,6 +1202,7 @@ def _reset_empty_waiter(self): def close(self): self._read_ready_cb = None + self._write_ready = None super().close() diff --git a/Misc/ACKS b/Misc/ACKS index 454b63155f013c..ef0029a7e4119d 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -615,6 +615,7 @@ Marius Gedminas Jan-Philip Gehrcke Thomas Gellekum Gabriel Genellina +Andrew Geng Philip Georgi Christos Georgiou Elazar (אלעזר) Gershuni diff --git a/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst new file mode 100644 index 00000000000000..b8dd850386e86c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst @@ -0,0 +1,2 @@ +Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by removing +``_write_ready`` in ``close``. From 363f4f99c524a6d763d1548986a79c42cc7ca292 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 7 Jul 2023 14:10:07 +0100 Subject: [PATCH 298/446] gh-104683: clinic.py: refactor `Parameter` and `Function` as dataclasses (#106477) --- Tools/clinic/clinic.py | 143 ++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 86 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 24d6255f262da4..19c5f573920cb9 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2439,6 +2439,8 @@ def __repr__(self) -> str: ParamDict = dict[str, "Parameter"] ReturnConverterType = Callable[..., "CReturnConverter"] + +@dc.dataclass(repr=False) class Function: """ Mutable duck type for inspect.Function. @@ -2450,49 +2452,34 @@ class Function: It will always be true that (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) """ + parameters: ParamDict = dc.field(default_factory=dict) + _: dc.KW_ONLY + name: str + module: Module + cls: Class | None = None + c_basename: str | None = None + full_name: str | None = None + return_converter: CReturnConverter + return_annotation: object = inspect.Signature.empty + docstring: str = '' + kind: str = CALLABLE + coexist: bool = False + # docstring_only means "don't generate a machine-readable + # signature, just a normal docstring". it's True for + # functions with optional groups because we can't represent + # those accurately with inspect.Signature in 3.4. + docstring_only: bool = False - def __init__( - self, - parameters: ParamDict | None = None, - *, - name: str, - module: Module, - cls: Class | None = None, - c_basename: str | None = None, - full_name: str | None = None, - return_converter: CReturnConverter, - return_annotation = inspect.Signature.empty, - docstring: str | None = None, - kind: str = CALLABLE, - coexist: bool = False, - docstring_only: bool = False - ) -> None: - self.parameters = parameters or {} - self.return_annotation = return_annotation - self.name = name - self.full_name = full_name - self.module = module - self.cls = cls - self.parent = cls or module - self.c_basename = c_basename - self.return_converter = return_converter - self.docstring = docstring or '' - self.kind = kind - self.coexist = coexist + def __post_init__(self) -> None: + self.parent: Class | Module = self.cls or self.module self.self_converter: self_converter | None = None - # docstring_only means "don't generate a machine-readable - # signature, just a normal docstring". it's True for - # functions with optional groups because we can't represent - # those accurately with inspect.Signature in 3.4. - self.docstring_only = docstring_only - - self.rendered_parameters = None + self.__render_parameters__: list[Parameter] | None = None - __render_parameters__ = None @property - def render_parameters(self): + def render_parameters(self) -> list[Parameter]: if not self.__render_parameters__: - self.__render_parameters__ = l = [] + l: list[Parameter] = [] + self.__render_parameters__ = l for p in self.parameters.values(): p = p.copy() p.converter.pre_render() @@ -2517,17 +2504,8 @@ def methoddef_flags(self) -> str | None: def __repr__(self) -> str: return '' - def copy(self, **overrides) -> "Function": - kwargs = { - 'name': self.name, 'module': self.module, 'parameters': self.parameters, - 'cls': self.cls, 'c_basename': self.c_basename, - 'full_name': self.full_name, - 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, - 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, - 'docstring_only': self.docstring_only, - } - kwargs.update(overrides) - f = Function(**kwargs) + def copy(self, **overrides: Any) -> Function: + f = dc.replace(self, **overrides) f.parameters = { name: value.copy(function=f) for name, value in f.parameters.items() @@ -2535,31 +2513,21 @@ def copy(self, **overrides) -> "Function": return f +@dc.dataclass(repr=False, slots=True) class Parameter: """ Mutable duck type of inspect.Parameter. """ - - def __init__( - self, - name: str, - kind: inspect._ParameterKind, - *, - default = inspect.Parameter.empty, - function: Function, - converter: "CConverter", - annotation = inspect.Parameter.empty, - docstring: str | None = None, - group: int = 0 - ) -> None: - self.name = name - self.kind = kind - self.default = default - self.function = function - self.converter = converter - self.annotation = annotation - self.docstring = docstring or '' - self.group = group + name: str + kind: inspect._ParameterKind + _: dc.KW_ONLY + default: object = inspect.Parameter.empty + function: Function + converter: CConverter + annotation: object = inspect.Parameter.empty + docstring: str = '' + group: int = 0 + right_bracket_count: int = dc.field(init=False, default=0) def __repr__(self) -> str: return '' @@ -2576,18 +2544,19 @@ def is_vararg(self) -> bool: def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) - def copy(self, **overrides) -> "Parameter": - kwargs = { - 'name': self.name, 'kind': self.kind, 'default':self.default, - 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, - 'docstring': self.docstring, 'group': self.group, - } - kwargs.update(overrides) - if 'converter' not in overrides: + def copy( + self, + /, + *, + converter: CConverter | None = None, + function: Function | None = None, + **overrides: Any + ) -> Parameter: + function = function or self.function + if not converter: converter = copy.copy(self.converter) - converter.function = kwargs['function'] - kwargs['converter'] = converter - return Parameter(**kwargs) + converter.function = function + return dc.replace(self, **overrides, function=function, converter=converter) def get_displayname(self, i: int) -> str: if i == 0: @@ -2761,7 +2730,7 @@ def __init__(self, # Positional args: name: str, py_name: str, - function, + function: Function, default: object = unspecified, *, # Keyword only args: c_default: str | None = None, @@ -2800,7 +2769,9 @@ def __init__(self, # about the function in the init. # (that breaks if we get cloned.) # so after this change we will noisily fail. - self.function = LandMine("Don't access members of self.function inside converter_init!") + self.function: Function | LandMine = LandMine( + "Don't access members of self.function inside converter_init!" + ) self.converter_init(**kwargs) self.function = function @@ -2810,7 +2781,7 @@ def converter_init(self): def is_optional(self) -> bool: return (self.default is not unspecified) - def _render_self(self, parameter: str, data: CRenderData) -> None: + def _render_self(self, parameter: Parameter, data: CRenderData) -> None: self.parameter = parameter name = self.parser_name @@ -2870,7 +2841,7 @@ def _render_non_self(self, parameter, data): if cleanup: data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") - def render(self, parameter: str, data: CRenderData) -> None: + def render(self, parameter: Parameter, data: CRenderData) -> None: """ parameter is a clinic.Parameter instance. data is a CRenderData instance. @@ -5246,7 +5217,7 @@ def format_docstring(self): assert isinstance(parameters[0].converter, self_converter) # self is always positional-only. assert parameters[0].is_positional_only() - parameters[0].right_bracket_count = 0 + assert parameters[0].right_bracket_count == 0 positional_only = True for p in parameters[1:]: if not p.is_positional_only(): From 11038c56ad80dde2cdf65190e78a59d579c94b3a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 7 Jul 2023 10:42:10 -0700 Subject: [PATCH 299/446] gh-104584: Move super-instruction special-casing to generator (#106500) Instead of special-casing specific instructions, we add a few more special values to the 'size' field of expansions, so in the future we can automatically handle additional super-instructions in the generator. --- Python/opcode_metadata.h | 9 ++++ Python/optimizer.c | 53 +++++++-------------- Tools/cases_generator/generate_cases.py | 61 ++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ac86a4abd9c1b3..d29f7216ea65e9 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -934,6 +934,12 @@ struct opcode_macro_expansion { struct { int16_t uop; int8_t size; int8_t offset; } uops[8]; }; +#define OPARG_FULL 0 +#define OPARG_CACHE_1 1 +#define OPARG_CACHE_2 2 +#define OPARG_CACHE_4 4 +#define OPARG_TOP 5 +#define OPARG_BOTTOM 6 #define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ @@ -1165,8 +1171,11 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } }, [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { LOAD_FAST_AND_CLEAR, 0, 0 } } }, + [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { LOAD_FAST, 5, 0 }, { LOAD_FAST, 6, 0 } } }, [LOAD_CONST] = { .nuops = 1, .uops = { { LOAD_CONST, 0, 0 } } }, [STORE_FAST] = { .nuops = 1, .uops = { { STORE_FAST, 0, 0 } } }, + [STORE_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { STORE_FAST, 5, 0 }, { LOAD_FAST, 6, 0 } } }, + [STORE_FAST_STORE_FAST] = { .nuops = 2, .uops = { { STORE_FAST, 5, 0 }, { STORE_FAST, 6, 0 } } }, [POP_TOP] = { .nuops = 1, .uops = { { POP_TOP, 0, 0 } } }, [PUSH_NULL] = { .nuops = 1, .uops = { { PUSH_NULL, 0, 0 } } }, [END_FOR] = { .nuops = 2, .uops = { { POP_TOP, 0, 0 }, { POP_TOP, 0, 0 } } }, diff --git a/Python/optimizer.c b/Python/optimizer.c index db117bb180c1c8..2870f2fd05052e 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -411,44 +411,15 @@ translate_bytecode_to_trace( for (;;) { ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); int opcode = instr->op.code; - uint64_t operand = instr->op.arg; + int oparg = instr->op.arg; int extras = 0; while (opcode == EXTENDED_ARG) { instr++; extras += 1; opcode = instr->op.code; - operand = (operand << 8) | instr->op.arg; + oparg = (oparg << 8) | instr->op.arg; } switch (opcode) { - case LOAD_FAST_LOAD_FAST: - case STORE_FAST_LOAD_FAST: - case STORE_FAST_STORE_FAST: - { - // Reserve space for two uops (+ SAVE_IP + EXIT_TRACE) - if (trace_length + 4 > max_length) { - DPRINTF(1, "Ran out of space for LOAD_FAST_LOAD_FAST\n"); - goto done; - } - uint64_t oparg1 = operand >> 4; - uint64_t oparg2 = operand & 15; - switch (opcode) { - case LOAD_FAST_LOAD_FAST: - ADD_TO_TRACE(LOAD_FAST, oparg1); - ADD_TO_TRACE(LOAD_FAST, oparg2); - break; - case STORE_FAST_LOAD_FAST: - ADD_TO_TRACE(STORE_FAST, oparg1); - ADD_TO_TRACE(LOAD_FAST, oparg2); - break; - case STORE_FAST_STORE_FAST: - ADD_TO_TRACE(STORE_FAST, oparg1); - ADD_TO_TRACE(STORE_FAST, oparg2); - break; - default: - Py_FatalError("Missing case"); - } - break; - } default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -462,9 +433,11 @@ translate_bytecode_to_trace( goto done; } for (int i = 0; i < nuops; i++) { + uint64_t operand; int offset = expansion->uops[i].offset; switch (expansion->uops[i].size) { - case 0: + case OPARG_FULL: + operand = oparg; if (extras && OPCODE_HAS_JUMP(opcode)) { if (opcode == JUMP_BACKWARD_NO_INTERRUPT) { operand -= extras; @@ -475,19 +448,25 @@ translate_bytecode_to_trace( } } break; - case 1: + case OPARG_CACHE_1: operand = read_u16(&instr[offset].cache); break; - case 2: + case OPARG_CACHE_2: operand = read_u32(&instr[offset].cache); break; - case 4: + case OPARG_CACHE_4: operand = read_u64(&instr[offset].cache); break; + case OPARG_TOP: // First half of super-instr + operand = oparg >> 4; + break; + case OPARG_BOTTOM: // Second half of super-instr + operand = oparg & 0xF; + break; default: fprintf(stderr, - "opcode=%d, operand=%" PRIu64 "; nuops=%d, i=%d; size=%d, offset=%d\n", - opcode, operand, nuops, i, + "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n", + opcode, oparg, nuops, i, expansion->uops[i].size, expansion->uops[i].offset); Py_FatalError("garbled expansion"); diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a90abfe20c1739..632834ce231664 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -40,6 +40,17 @@ UNUSED = "unused" BITS_PER_CODE_UNIT = 16 +# Constants used instead of size for macro expansions. +# Note: 1, 2, 4 must match actual cache entry sizes. +OPARG_SIZES = { + "OPARG_FULL": 0, + "OPARG_CACHE_1": 1, + "OPARG_CACHE_2": 2, + "OPARG_CACHE_4": 4, + "OPARG_TOP": 5, + "OPARG_BOTTOM": 6, +} + RESERVED_WORDS = { "co_consts" : "Use FRAME_CO_CONSTS.", "co_names": "Use FRAME_CO_NAMES.", @@ -1213,7 +1224,10 @@ def write_metadata(self) -> None: self.out.emit("struct { int16_t uop; int8_t size; int8_t offset; } uops[8];") self.out.emit("") + for key, value in OPARG_SIZES.items(): + self.out.emit(f"#define {key} {value}") self.out.emit("") + self.out.emit("#define OPCODE_METADATA_FMT(OP) " "(_PyOpcode_opcode_metadata[(OP)].instr_format)") self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\") @@ -1263,6 +1277,9 @@ def write_metadata(self) -> None: # Construct a dummy Component -- input/output mappings are not used part = Component(instr, [], [], instr.active_caches) self.write_macro_expansions(instr.name, [part]) + elif instr.kind == "inst" and variable_used(instr.inst, "oparg1"): + assert variable_used(instr.inst, "oparg2"), "Half super-instr?" + self.write_super_expansions(instr.name) case parser.Macro(): mac = self.macro_instrs[thing.name] self.write_macro_expansions(mac.name, mac.parts) @@ -1342,7 +1359,7 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None: print(f"NOTE: Part {part.instr.name} of {name} is not a viable uop") return if part.instr.instr_flags.HAS_ARG_FLAG or not part.active_caches: - size, offset = 0, 0 + size, offset = OPARG_SIZES["OPARG_FULL"], 0 else: # If this assert triggers, is_viable_uops() lied assert len(part.active_caches) == 1, (name, part.instr.name) @@ -1350,10 +1367,50 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None: size, offset = cache.effect.size, cache.offset expansions.append((part.instr.name, size, offset)) assert len(expansions) > 0, f"Macro {name} has empty expansion?!" + self.write_expansions(name, expansions) + + def write_super_expansions(self, name: str) -> None: + """Write special macro expansions for super-instructions. + + If you get an assertion failure here, you probably have accidentally + violated one of the assumptions here. + + - A super-instruction's name is of the form FIRST_SECOND where + FIRST and SECOND are regular instructions whose name has the + form FOO_BAR. Thus, there must be exactly 3 underscores. + Example: LOAD_CONST_STORE_FAST. + + - A super-instruction's body uses `oparg1 and `oparg2`, and no + other instruction's body uses those variable names. + + - A super-instruction has no active (used) cache entries. + + In the expansion, the first instruction's operand is all but the + bottom 4 bits of the super-instruction's oparg, and the second + instruction's operand is the bottom 4 bits. We use the special + size codes OPARG_TOP and OPARG_BOTTOM for these. + """ + pieces = name.split("_") + assert len(pieces) == 4, f"{name} doesn't look like a super-instr" + name1 = "_".join(pieces[:2]) + name2 = "_".join(pieces[2:]) + assert name1 in self.instrs, f"{name1} doesn't match any instr" + assert name2 in self.instrs, f"{name2} doesn't match any instr" + instr1 = self.instrs[name1] + instr2 = self.instrs[name2] + assert not instr1.active_caches, f"{name1} has active caches" + assert not instr2.active_caches, f"{name2} has active caches" + expansions = [ + (name1, OPARG_SIZES["OPARG_TOP"], 0), + (name2, OPARG_SIZES["OPARG_BOTTOM"], 0), + ] + self.write_expansions(name, expansions) + + def write_expansions(self, name: str, expansions: list[tuple[str, int, int]]) -> None: pieces = [f"{{ {name}, {size}, {offset} }}" for name, size, offset in expansions] self.out.emit( f"[{name}] = " - f"{{ .nuops = {len(expansions)}, .uops = {{ {', '.join(pieces)} }} }}," + f"{{ .nuops = {len(pieces)}, .uops = {{ {', '.join(pieces)} }} }}," ) def emit_metadata_entry( From b3648f036e502db7e7da951ec4eb1f205cb3d74e Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 7 Jul 2023 11:03:27 -0700 Subject: [PATCH 300/446] gh-104584: Allow unspecialized instructions in superblocks (#106497) This adds several of unspecialized opcodes to superblocks: TO_BOOL, BINARY_SUBSCR, STORE_SUBSCR, UNPACK_SEQUENCE, LOAD_GLOBAL, LOAD_ATTR, COMPARE_OP, BINARY_OP. While we may not want that eventually, for now this helps finding bugs. There is a rudimentary test checking for UNPACK_SEQUENCE. Once we're ready to undo this, that would be simple: just replace the call to variable_used_unspecialized with a call to variable_used (as shown in a comment). Or add individual opcdes to FORBIDDEN_NAMES_IN_UOPS. --- Lib/test/test_capi/test_misc.py | 28 ++ Python/executor_cases.c.h | 556 ++++++++++++++++++------ Python/opcode_metadata.h | 8 + Tools/cases_generator/generate_cases.py | 26 +- 4 files changed, 490 insertions(+), 128 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 181e6b8077f9f5..5f39f23401c3f2 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2499,6 +2499,34 @@ def many_vars(): ex = get_first_executor(many_vars.__code__) self.assertIn(("LOAD_FAST", 259), list(ex)) + def test_unspecialized_unpack(self): + # An example of an unspecialized opcode + def testfunc(x): + i = 0 + while i < x: + i += 1 + a, b = {1: 2, 3: 3} + assert a == 1 and b == 3 + i = 0 + while i < x: + i += 1 + + opt = _testinternalcapi.get_uop_optimizer() + + with temporary_optimizer(opt): + testfunc(10) + + ex = None + for offset in range(0, len(testfunc.__code__.co_code), 2): + try: + ex = _testinternalcapi.get_executor(testfunc.__code__, offset) + break + except ValueError: + pass + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("UNPACK_SEQUENCE", uops) + if __name__ == "__main__": unittest.main() diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 29ebb0b3e8b2d9..32efeb099d9b3e 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -118,12 +118,38 @@ break; } + case TO_BOOL: { + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 296 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_ToBool(value, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(TO_BOOL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + int err = PyObject_IsTrue(value); + #line 138 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 308 "Python/bytecodes.c" + if (err < 0) goto pop_1_error; + res = err ? Py_True : Py_False; + #line 143 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + case TO_BOOL_BOOL: { PyObject *value = stack_pointer[-1]; #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 127 "Python/executor_cases.c.h" + #line 153 "Python/executor_cases.c.h" break; } @@ -138,12 +164,12 @@ res = Py_False; } else { - #line 142 "Python/executor_cases.c.h" + #line 168 "Python/executor_cases.c.h" Py_DECREF(value); #line 326 "Python/bytecodes.c" res = Py_True; } - #line 147 "Python/executor_cases.c.h" + #line 173 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -155,7 +181,7 @@ DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; - #line 159 "Python/executor_cases.c.h" + #line 185 "Python/executor_cases.c.h" Py_DECREF(value); stack_pointer[-1] = res; break; @@ -169,7 +195,7 @@ DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_False; - #line 173 "Python/executor_cases.c.h" + #line 199 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -186,12 +212,12 @@ } else { assert(Py_SIZE(value)); - #line 190 "Python/executor_cases.c.h" + #line 216 "Python/executor_cases.c.h" Py_DECREF(value); #line 354 "Python/bytecodes.c" res = Py_True; } - #line 195 "Python/executor_cases.c.h" + #line 221 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -205,11 +231,11 @@ assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 209 "Python/executor_cases.c.h" + #line 235 "Python/executor_cases.c.h" Py_DECREF(value); #line 364 "Python/bytecodes.c" res = Py_True; - #line 213 "Python/executor_cases.c.h" + #line 239 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -219,11 +245,11 @@ PyObject *res; #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 223 "Python/executor_cases.c.h" + #line 249 "Python/executor_cases.c.h" Py_DECREF(value); #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 227 "Python/executor_cases.c.h" + #line 253 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -234,7 +260,7 @@ #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 238 "Python/executor_cases.c.h" + #line 264 "Python/executor_cases.c.h" break; } @@ -248,7 +274,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 252 "Python/executor_cases.c.h" + #line 278 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -264,7 +290,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 268 "Python/executor_cases.c.h" + #line 294 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -280,7 +306,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 284 "Python/executor_cases.c.h" + #line 310 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -292,7 +318,7 @@ #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 296 "Python/executor_cases.c.h" + #line 322 "Python/executor_cases.c.h" break; } @@ -306,7 +332,7 @@ ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 310 "Python/executor_cases.c.h" + #line 336 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -322,7 +348,7 @@ ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 326 "Python/executor_cases.c.h" + #line 352 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -338,7 +364,7 @@ ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 342 "Python/executor_cases.c.h" + #line 368 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -350,7 +376,7 @@ #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 354 "Python/executor_cases.c.h" + #line 380 "Python/executor_cases.c.h" break; } @@ -364,7 +390,35 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 368 "Python/executor_cases.c.h" + #line 394 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case BINARY_SUBSCR: { + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); + PyObject *sub = stack_pointer[-1]; + PyObject *container = stack_pointer[-2]; + PyObject *res; + #line 517 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_BinarySubscr(container, sub, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BINARY_SUBSCR, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + res = PyObject_GetItem(container, sub); + #line 417 "Python/executor_cases.c.h" + Py_DECREF(container); + Py_DECREF(sub); + #line 529 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + #line 422 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -388,7 +442,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 392 "Python/executor_cases.c.h" + #line 446 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -412,7 +466,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 416 "Python/executor_cases.c.h" + #line 470 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -435,7 +489,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 439 "Python/executor_cases.c.h" + #line 493 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -459,7 +513,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 463 "Python/executor_cases.c.h" + #line 517 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -477,14 +531,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 481 "Python/executor_cases.c.h" + #line 535 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 488 "Python/executor_cases.c.h" + #line 542 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -497,7 +551,7 @@ PyObject *list = stack_pointer[-(2 + (oparg-1))]; #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 501 "Python/executor_cases.c.h" + #line 555 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -507,15 +561,47 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 511 "Python/executor_cases.c.h" + #line 565 "Python/executor_cases.c.h" Py_DECREF(v); #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 515 "Python/executor_cases.c.h" + #line 569 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } + case STORE_SUBSCR: { + static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); + PyObject *sub = stack_pointer[-1]; + PyObject *container = stack_pointer[-2]; + PyObject *v = stack_pointer[-3]; + uint16_t counter = (uint16_t)operand; + #line 651 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + next_instr--; + _Py_Specialize_StoreSubscr(container, sub, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(STORE_SUBSCR, deferred); + _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + (void)counter; // Unused. + #endif /* ENABLE_SPECIALIZATION */ + /* container[sub] = v */ + int err = PyObject_SetItem(container, sub, v); + #line 595 "Python/executor_cases.c.h" + Py_DECREF(v); + Py_DECREF(container); + Py_DECREF(sub); + #line 666 "Python/bytecodes.c" + if (err) goto pop_3_error; + #line 601 "Python/executor_cases.c.h" + STACK_SHRINK(3); + break; + } + case STORE_SUBSCR_LIST_INT: { PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; @@ -537,7 +623,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 541 "Python/executor_cases.c.h" + #line 627 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -552,7 +638,7 @@ int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 556 "Python/executor_cases.c.h" + #line 642 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -563,12 +649,12 @@ #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 567 "Python/executor_cases.c.h" + #line 653 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 572 "Python/executor_cases.c.h" + #line 658 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -579,11 +665,11 @@ #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 583 "Python/executor_cases.c.h" + #line 669 "Python/executor_cases.c.h" Py_DECREF(value); #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 587 "Python/executor_cases.c.h" + #line 673 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -595,12 +681,12 @@ #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 599 "Python/executor_cases.c.h" + #line 685 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 604 "Python/executor_cases.c.h" + #line 690 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -622,14 +708,14 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 626 "Python/executor_cases.c.h" + #line 712 "Python/executor_cases.c.h" Py_DECREF(obj); #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 633 "Python/executor_cases.c.h" + #line 719 "Python/executor_cases.c.h" Py_DECREF(obj); #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; @@ -644,7 +730,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 648 "Python/executor_cases.c.h" + #line 734 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -695,7 +781,7 @@ Py_DECREF(next_iter); } } - #line 699 "Python/executor_cases.c.h" + #line 785 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -711,7 +797,7 @@ format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 715 "Python/executor_cases.c.h" + #line 801 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 904 "Python/bytecodes.c" @@ -730,7 +816,7 @@ } if (iter == NULL) goto pop_1_error; - #line 734 "Python/executor_cases.c.h" + #line 820 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -740,7 +826,7 @@ #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 744 "Python/executor_cases.c.h" + #line 830 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -749,7 +835,7 @@ PyObject *value; #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 753 "Python/executor_cases.c.h" + #line 839 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -779,7 +865,7 @@ if (true) goto error; } } - #line 783 "Python/executor_cases.c.h" + #line 869 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -794,7 +880,7 @@ if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 798 "Python/executor_cases.c.h" + #line 884 "Python/executor_cases.c.h" Py_DECREF(v); #line 1121 "Python/bytecodes.c" if (true) goto pop_1_error; @@ -803,11 +889,11 @@ err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 807 "Python/executor_cases.c.h" + #line 893 "Python/executor_cases.c.h" Py_DECREF(v); #line 1128 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 811 "Python/executor_cases.c.h" + #line 897 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -830,7 +916,33 @@ name); goto error; } - #line 834 "Python/executor_cases.c.h" + #line 920 "Python/executor_cases.c.h" + break; + } + + case UNPACK_SEQUENCE: { + static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); + PyObject *seq = stack_pointer[-1]; + #line 1158 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_UnpackSequence(seq, next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(UNPACK_SEQUENCE, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject **top = stack_pointer + oparg - 1; + int res = unpack_iterable(tstate, seq, oparg, -1, top); + #line 940 "Python/executor_cases.c.h" + Py_DECREF(seq); + #line 1171 "Python/bytecodes.c" + if (res == 0) goto pop_1_error; + #line 944 "Python/executor_cases.c.h" + STACK_SHRINK(1); + STACK_GROW(oparg); break; } @@ -844,7 +956,7 @@ STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 848 "Python/executor_cases.c.h" + #line 960 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -862,7 +974,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 866 "Python/executor_cases.c.h" + #line 978 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -880,7 +992,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 884 "Python/executor_cases.c.h" + #line 996 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -893,11 +1005,11 @@ int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 897 "Python/executor_cases.c.h" + #line 1009 "Python/executor_cases.c.h" Py_DECREF(seq); #line 1211 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 901 "Python/executor_cases.c.h" + #line 1013 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } @@ -907,11 +1019,11 @@ #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 911 "Python/executor_cases.c.h" + #line 1023 "Python/executor_cases.c.h" Py_DECREF(owner); #line 1245 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 915 "Python/executor_cases.c.h" + #line 1027 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -921,11 +1033,11 @@ #line 1249 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 925 "Python/executor_cases.c.h" + #line 1037 "Python/executor_cases.c.h" Py_DECREF(v); #line 1252 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 929 "Python/executor_cases.c.h" + #line 1041 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -943,7 +1055,7 @@ } goto error; } - #line 947 "Python/executor_cases.c.h" + #line 1059 "Python/executor_cases.c.h" break; } @@ -957,7 +1069,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 961 "Python/executor_cases.c.h" + #line 1073 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -1023,17 +1135,81 @@ } } } - #line 1027 "Python/executor_cases.c.h" + #line 1139 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } + case LOAD_GLOBAL: { + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyObject *null = NULL; + PyObject *v; + #line 1351 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + next_instr--; + _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(LOAD_GLOBAL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) + { + v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + /* _PyDict_LoadGlobal() returns NULL without raising + * an exception if the key doesn't exist */ + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + if (true) goto error; + } + Py_INCREF(v); + } + else { + /* Slow-path if globals or builtins is not a dict */ + + /* namespace 1: globals */ + v = PyObject_GetItem(GLOBALS(), name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; + _PyErr_Clear(tstate); + + /* namespace 2: builtins */ + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + if (true) goto error; + } + } + } + null = NULL; + #line 1200 "Python/executor_cases.c.h" + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = v; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } + break; + } + case DELETE_FAST: { #line 1435 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1037 "Python/executor_cases.c.h" + #line 1213 "Python/executor_cases.c.h" break; } @@ -1049,7 +1225,7 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1053 "Python/executor_cases.c.h" + #line 1229 "Python/executor_cases.c.h" break; } @@ -1091,7 +1267,7 @@ } Py_INCREF(value); } - #line 1095 "Python/executor_cases.c.h" + #line 1271 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } @@ -1106,7 +1282,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1110 "Python/executor_cases.c.h" + #line 1286 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1119,7 +1295,7 @@ PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1123 "Python/executor_cases.c.h" + #line 1299 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1136,7 +1312,7 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1140 "Python/executor_cases.c.h" + #line 1316 "Python/executor_cases.c.h" break; } @@ -1145,13 +1321,13 @@ PyObject *str; #line 1532 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1149 "Python/executor_cases.c.h" + #line 1325 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } #line 1534 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1155 "Python/executor_cases.c.h" + #line 1331 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1164,7 +1340,7 @@ #line 1538 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1168 "Python/executor_cases.c.h" + #line 1344 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1177,7 +1353,7 @@ #line 1543 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1181 "Python/executor_cases.c.h" + #line 1357 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1198,13 +1374,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1202 "Python/executor_cases.c.h" + #line 1378 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1208 "Python/executor_cases.c.h" + #line 1384 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1215,11 +1391,11 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 1566 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1219 "Python/executor_cases.c.h" + #line 1395 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1568 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1223 "Python/executor_cases.c.h" + #line 1399 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1242,7 +1418,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1246 "Python/executor_cases.c.h" + #line 1422 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1260,13 +1436,13 @@ if (map == NULL) goto error; - #line 1264 "Python/executor_cases.c.h" + #line 1440 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } #line 1597 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1270 "Python/executor_cases.c.h" + #line 1446 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1314,7 +1490,7 @@ Py_DECREF(ann_dict); } } - #line 1318 "Python/executor_cases.c.h" + #line 1494 "Python/executor_cases.c.h" break; } @@ -1332,14 +1508,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1336 "Python/executor_cases.c.h" + #line 1512 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); #line 1653 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1343 "Python/executor_cases.c.h" + #line 1519 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1355,12 +1531,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1359 "Python/executor_cases.c.h" + #line 1535 "Python/executor_cases.c.h" Py_DECREF(update); #line 1665 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1364 "Python/executor_cases.c.h" + #line 1540 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1373,12 +1549,12 @@ if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1377 "Python/executor_cases.c.h" + #line 1553 "Python/executor_cases.c.h" Py_DECREF(update); #line 1676 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1382 "Python/executor_cases.c.h" + #line 1558 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1393,7 +1569,7 @@ /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1397 "Python/executor_cases.c.h" + #line 1573 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1411,13 +1587,13 @@ STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1415 "Python/executor_cases.c.h" + #line 1591 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); #line 1772 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1421 "Python/executor_cases.c.h" + #line 1597 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1454,13 +1630,110 @@ res = res2; res2 = NULL; } - #line 1458 "Python/executor_cases.c.h" + #line 1634 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; break; } + case LOAD_ATTR: { + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + PyObject *owner = stack_pointer[-1]; + PyObject *res2 = NULL; + PyObject *res; + #line 1815 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + next_instr--; + _Py_Specialize_LoadAttr(owner, next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(LOAD_ATTR, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); + if (oparg & 1) { + /* Designed to work in tandem with CALL, pushes two values. */ + PyObject* meth = NULL; + if (_PyObject_GetMethod(owner, name, &meth)) { + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + + meth | self | arg1 | ... | argN + */ + assert(meth != NULL); // No errors on this branch + res2 = meth; + res = owner; // Transfer ownership + } + else { + /* meth is not an unbound method (but a regular attr, or + something was returned by a descriptor protocol). Set + the second element of the stack to NULL, to signal + CALL that it's not a method call. + + NULL | meth | arg1 | ... | argN + */ + #line 1680 "Python/executor_cases.c.h" + Py_DECREF(owner); + #line 1849 "Python/bytecodes.c" + if (meth == NULL) goto pop_1_error; + res2 = NULL; + res = meth; + } + } + else { + /* Classic, pushes one value. */ + res = PyObject_GetAttr(owner, name); + #line 1691 "Python/executor_cases.c.h" + Py_DECREF(owner); + #line 1858 "Python/bytecodes.c" + if (res == NULL) goto pop_1_error; + } + #line 1696 "Python/executor_cases.c.h" + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + break; + } + + case COMPARE_OP: { + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *res; + #line 2091 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_CompareOp(left, right, next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(COMPARE_OP, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + assert((oparg >> 5) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg >> 5); + #line 1721 "Python/executor_cases.c.h" + Py_DECREF(left); + Py_DECREF(right); + #line 2104 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res); + Py_DECREF(res); + if (res_bool < 0) goto pop_2_error; + res = res_bool ? Py_True : Py_False; + } + #line 1732 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case COMPARE_OP_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -1477,7 +1750,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1481 "Python/executor_cases.c.h" + #line 1754 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1503,7 +1776,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1507 "Python/executor_cases.c.h" + #line 1780 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1526,7 +1799,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1530 "Python/executor_cases.c.h" + #line 1803 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1538,12 +1811,12 @@ PyObject *b; #line 2163 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1542 "Python/executor_cases.c.h" + #line 1815 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2165 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1547 "Python/executor_cases.c.h" + #line 1820 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1555,13 +1828,13 @@ PyObject *b; #line 2169 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1559 "Python/executor_cases.c.h" + #line 1832 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2171 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1565 "Python/executor_cases.c.h" + #line 1838 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1574,7 +1847,7 @@ PyObject *match; #line 2176 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1578 "Python/executor_cases.c.h" + #line 1851 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2178 "Python/bytecodes.c" @@ -1585,7 +1858,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1589 "Python/executor_cases.c.h" + #line 1862 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2186 "Python/bytecodes.c" @@ -1597,7 +1870,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1601 "Python/executor_cases.c.h" + #line 1874 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1610,18 +1883,18 @@ #line 2197 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1614 "Python/executor_cases.c.h" + #line 1887 "Python/executor_cases.c.h" Py_DECREF(right); #line 2200 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1621 "Python/executor_cases.c.h" + #line 1894 "Python/executor_cases.c.h" Py_DECREF(right); #line 2205 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1625 "Python/executor_cases.c.h" + #line 1898 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1635,7 +1908,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1639 "Python/executor_cases.c.h" + #line 1912 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1651,7 +1924,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1655 "Python/executor_cases.c.h" + #line 1928 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -1663,7 +1936,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1667 "Python/executor_cases.c.h" + #line 1940 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1675,7 +1948,7 @@ #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1679 "Python/executor_cases.c.h" + #line 1952 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1687,7 +1960,7 @@ #line 2337 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1691 "Python/executor_cases.c.h" + #line 1964 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1701,7 +1974,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1705 "Python/executor_cases.c.h" + #line 1978 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1713,11 +1986,11 @@ #line 2348 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1717 "Python/executor_cases.c.h" + #line 1990 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2351 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1721 "Python/executor_cases.c.h" + #line 1994 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1748,11 +2021,11 @@ if (iter == NULL) { goto error; } - #line 1752 "Python/executor_cases.c.h" + #line 2025 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2378 "Python/bytecodes.c" } - #line 1756 "Python/executor_cases.c.h" + #line 2029 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1783,7 +2056,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 1787 "Python/executor_cases.c.h" + #line 2060 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1802,7 +2075,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 1806 "Python/executor_cases.c.h" + #line 2079 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -1819,7 +2092,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 1823 "Python/executor_cases.c.h" + #line 2096 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1839,7 +2112,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 1843 "Python/executor_cases.c.h" + #line 2116 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -1872,7 +2145,7 @@ default: Py_UNREACHABLE(); } - #line 1876 "Python/executor_cases.c.h" + #line 2149 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -1885,13 +2158,13 @@ PyObject *slice; #line 3497 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 1889 "Python/executor_cases.c.h" + #line 2162 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3499 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 1895 "Python/executor_cases.c.h" + #line 2168 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -1908,7 +2181,7 @@ result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 1912 "Python/executor_cases.c.h" + #line 2185 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -1927,7 +2200,7 @@ else { res = value; } - #line 1931 "Python/executor_cases.c.h" + #line 2204 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -1941,7 +2214,7 @@ Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 1945 "Python/executor_cases.c.h" + #line 2218 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1953,18 +2226,49 @@ #line 3532 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 1957 "Python/executor_cases.c.h" + #line 2230 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; } + case BINARY_OP: { + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + PyObject *rhs = stack_pointer[-1]; + PyObject *lhs = stack_pointer[-2]; + PyObject *res; + #line 3537 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BINARY_OP, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + assert(0 <= oparg); + assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); + assert(binary_ops[oparg]); + res = binary_ops[oparg](lhs, rhs); + #line 2256 "Python/executor_cases.c.h" + Py_DECREF(lhs); + Py_DECREF(rhs); + #line 3552 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + #line 2261 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3557 "Python/bytecodes.c" assert(oparg >= 2); - #line 1968 "Python/executor_cases.c.h" + #line 2272 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index d29f7216ea65e9..70e1ca44ce7663 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -1182,6 +1182,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, + [TO_BOOL] = { .nuops = 1, .uops = { { TO_BOOL, 0, 0 } } }, [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } }, [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } }, [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } }, @@ -1196,6 +1197,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, + [BINARY_SUBSCR] = { .nuops = 1, .uops = { { BINARY_SUBSCR, 0, 0 } } }, [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, @@ -1203,6 +1205,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, + [STORE_SUBSCR] = { .nuops = 1, .uops = { { STORE_SUBSCR, 1, 0 } } }, [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, @@ -1216,6 +1219,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } }, [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } }, [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } }, + [UNPACK_SEQUENCE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE, 0, 0 } } }, [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } }, [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, @@ -1226,6 +1230,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, + [LOAD_GLOBAL] = { .nuops = 1, .uops = { { LOAD_GLOBAL, 0, 0 } } }, [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, @@ -1246,6 +1251,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } }, [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, + [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, + [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } }, @@ -1270,6 +1277,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } }, [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } }, [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, + [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; #ifdef NEED_OPCODE_METADATA diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 632834ce231664..14269ca8cbe750 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -425,8 +425,9 @@ def is_viable_uop(self) -> bool: return False res = True for forbidden in FORBIDDEN_NAMES_IN_UOPS: - # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions - if variable_used(self.inst, forbidden): + # NOTE: To disallow unspecialized uops, use + # if variable_used(self.inst, forbidden): + if variable_used_unspecialized(self.inst, forbidden): # print(f"Skipping {self.name} because it uses {forbidden}") res = False return res @@ -1644,6 +1645,27 @@ def variable_used(node: parser.Node, name: str) -> bool: ) +def variable_used_unspecialized(node: parser.Node, name: str) -> bool: + """Like variable_used(), but skips #if ENABLE_SPECIALIZATION blocks.""" + tokens: list[lx.Token] = [] + skipping = False + for i, token in enumerate(node.tokens): + if token.kind == "MACRO": + text = "".join(token.text.split()) + # TODO: Handle nested #if + if text == "#if": + if ( + i + 1 < len(node.tokens) + and node.tokens[i + 1].text == "ENABLE_SPECIALIZATION" + ): + skipping = True + elif text in ("#else", "#endif"): + skipping = False + if not skipping: + tokens.append(token) + return any(token.kind == "IDENTIFIER" and token.text == name for token in tokens) + + def main(): """Parse command line, parse input, analyze, write output.""" args = arg_parser.parse_args() # Prints message and sys.exit(2) on error From a8554588bad5ca9e890830281b8d70ecbf6f8e23 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 7 Jul 2023 13:16:19 -0500 Subject: [PATCH 301/446] Delete dead ceval code. (gh-106486) --- Python/ceval.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 0ee95bc3a3a4bb..1b8650a650412d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -763,11 +763,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); - if (_Py_HandlePending(tstate) != 0) { - goto error; - } - DISPATCH(); - { /* Start instructions */ #if !USE_COMPUTED_GOTOS From 80b9b3a51757ebb1e3547afc349a229706eadfde Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 7 Jul 2023 11:41:42 -0700 Subject: [PATCH 302/446] gh-104584: Replace ENTER_EXECUTOR with the original in trace projection (#106526) --- Python/optimizer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Python/optimizer.c b/Python/optimizer.c index 2870f2fd05052e..1d731ed2309c3c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -419,6 +419,12 @@ translate_bytecode_to_trace( opcode = instr->op.code; oparg = (oparg << 8) | instr->op.arg; } + if (opcode == ENTER_EXECUTOR) { + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; + opcode = executor->vm_data.opcode; + DPRINTF(2, " * ENTER_EXECUTOR -> %s\n", _PyOpcode_OpName[opcode]); + oparg = (oparg & 0xffffff00) | executor->vm_data.oparg; + } switch (opcode) { default: { From 6e6a4cd52332017b10c8d88fbbbfe015948093f4 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 7 Jul 2023 23:42:40 +0300 Subject: [PATCH 303/446] gh-106300: Improve `assertRaises(Exception)` usages in tests (GH-106302) --- Lib/test/test_abc.py | 5 +++-- Lib/test/test_codecs.py | 5 +++-- Lib/test/test_email/test_message.py | 6 ++++-- Lib/test/test_importlib/test_main.py | 2 +- Lib/test/test_mailbox.py | 7 +++++-- Lib/test/test_shutil.py | 2 +- Lib/test/test_unittest/testmock/testasync.py | 5 +++-- 7 files changed, 20 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 86f31a9acb4d55..5ce57cc209ea85 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -448,15 +448,16 @@ class S(metaclass=abc_ABCMeta): # Also check that issubclass() propagates exceptions raised by # __subclasses__. + class CustomError(Exception): ... exc_msg = "exception from __subclasses__" def raise_exc(): - raise Exception(exc_msg) + raise CustomError(exc_msg) class S(metaclass=abc_ABCMeta): __subclasses__ = raise_exc - with self.assertRaisesRegex(Exception, exc_msg): + with self.assertRaisesRegex(CustomError, exc_msg): issubclass(int, S) def test_subclasshook(self): diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index 376175f90f63eb..91d7eaf997ae20 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2822,14 +2822,15 @@ def test_binary_to_text_denylists_text_transforms(self): def test_custom_zlib_error_is_noted(self): # Check zlib codec gives a good error for malformed input msg = "decoding with 'zlib_codec' codec failed" - with self.assertRaises(Exception) as failure: + with self.assertRaises(zlib.error) as failure: codecs.decode(b"hello", "zlib_codec") self.assertEqual(msg, failure.exception.__notes__[0]) def test_custom_hex_error_is_noted(self): # Check hex codec gives a good error for malformed input + import binascii msg = "decoding with 'hex_codec' codec failed" - with self.assertRaises(Exception) as failure: + with self.assertRaises(binascii.Error) as failure: codecs.decode(b"hello", "hex_codec") self.assertEqual(msg, failure.exception.__notes__[0]) diff --git a/Lib/test/test_email/test_message.py b/Lib/test/test_email/test_message.py index 4c754bf40fc300..d3f396f02e7a72 100644 --- a/Lib/test/test_email/test_message.py +++ b/Lib/test/test_email/test_message.py @@ -696,14 +696,16 @@ def subtype_as_add(self, method, subtype, outcome): self.assertIsNone(part['Content-Disposition']) class _TestSetRaisingContentManager: + class CustomError(Exception): + pass def set_content(self, msg, content, *args, **kw): - raise Exception('test') + raise self.CustomError('test') def test_default_content_manager_for_add_comes_from_policy(self): cm = self._TestSetRaisingContentManager() m = self.message(policy=self.policy.clone(content_manager=cm)) for method in ('add_related', 'add_alternative', 'add_attachment'): - with self.assertRaises(Exception) as ar: + with self.assertRaises(self._TestSetRaisingContentManager.CustomError) as ar: getattr(m, method)('') self.assertEqual(str(ar.exception), 'test') diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py index 6469aad7130fce..3b49227255eb58 100644 --- a/Lib/test/test_importlib/test_main.py +++ b/Lib/test/test_importlib/test_main.py @@ -68,7 +68,7 @@ def test_abc_enforced(self): dict(name=''), ) def test_invalid_inputs_to_from_name(self, name): - with self.assertRaises(Exception): + with self.assertRaises(ValueError): Distribution.from_name(name) diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py index 4c592eaf34da23..4977a9369ddf88 100644 --- a/Lib/test/test_mailbox.py +++ b/Lib/test/test_mailbox.py @@ -116,10 +116,13 @@ def test_add_nonascii_string_header_raises(self): self.assertMailboxEmpty() def test_add_that_raises_leaves_mailbox_empty(self): + class CustomError(Exception): ... + exc_msg = "a fake error" + def raiser(*args, **kw): - raise Exception("a fake error") + raise CustomError(exc_msg) support.patch(self, email.generator.BytesGenerator, 'flatten', raiser) - with self.assertRaises(Exception): + with self.assertRaisesRegex(CustomError, exc_msg): self._box.add(email.message_from_string("From: Alphöso")) self.assertEqual(len(self._box), 0) self._box.close() diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 878a21a629f3cc..93f20a6ff41332 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2738,7 +2738,7 @@ def test_regular_copy(self): def test_same_file(self): self.addCleanup(self.reset) with self.get_files() as (src, dst): - with self.assertRaises(Exception): + with self.assertRaises((OSError, _GiveupOnFastCopy)): self.zerocopy_fun(src, src) # Make sure src file is not corrupted. self.assertEqual(read_file(TESTFN, binary=True), self.FILEDATA) diff --git a/Lib/test/test_unittest/testmock/testasync.py b/Lib/test/test_unittest/testmock/testasync.py index e9e1f63e84d4e7..f57b83f457f279 100644 --- a/Lib/test/test_unittest/testmock/testasync.py +++ b/Lib/test/test_unittest/testmock/testasync.py @@ -459,9 +459,10 @@ async def addition(self, var): pass self.assertEqual(output, 10) async def test_add_side_effect_exception(self): + class CustomError(Exception): pass async def addition(var): pass - mock = AsyncMock(addition, side_effect=Exception('err')) - with self.assertRaises(Exception): + mock = AsyncMock(addition, side_effect=CustomError('side-effect')) + with self.assertRaisesRegex(CustomError, 'side-effect'): await mock(5) async def test_add_side_effect_coroutine(self): From 1fb9bd222bfe96cdf8a82701a3192e45d0811555 Mon Sep 17 00:00:00 2001 From: Desmond Cheong Date: Fri, 7 Jul 2023 15:02:13 -0700 Subject: [PATCH 304/446] gh-103200: Fix performance issues with `zipimport.invalidate_caches()` (GH-103208) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Brett Cannon --- Lib/test/test_zipimport.py | 45 ++++++++++++++++-- Lib/zipimport.py | 46 ++++++++++--------- ...-04-03-08-09-40.gh-issue-103200.lq1Etz.rst | 1 + 3 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-04-03-08-09-40.gh-issue-103200.lq1Etz.rst diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 14c19719e260c4..c12798d221e9b7 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -520,10 +520,10 @@ def testInvalidateCaches(self): z.writestr(zinfo, data) zi = zipimport.zipimporter(TEMP_ZIP) - self.assertEqual(zi._files.keys(), files.keys()) + self.assertEqual(zi._get_files().keys(), files.keys()) # Check that the file information remains accurate after reloading zi.invalidate_caches() - self.assertEqual(zi._files.keys(), files.keys()) + self.assertEqual(zi._get_files().keys(), files.keys()) # Add a new file to the ZIP archive newfile = {"spam2" + pyc_ext: (NOW, test_pyc)} files.update(newfile) @@ -535,17 +535,54 @@ def testInvalidateCaches(self): z.writestr(zinfo, data) # Check that we can detect the new file after invalidating the cache zi.invalidate_caches() - self.assertEqual(zi._files.keys(), files.keys()) + self.assertEqual(zi._get_files().keys(), files.keys()) spec = zi.find_spec('spam2') self.assertIsNotNone(spec) self.assertIsInstance(spec.loader, zipimport.zipimporter) # Check that the cached data is removed if the file is deleted os.remove(TEMP_ZIP) zi.invalidate_caches() - self.assertFalse(zi._files) + self.assertFalse(zi._get_files()) self.assertIsNone(zipimport._zip_directory_cache.get(zi.archive)) self.assertIsNone(zi.find_spec("name_does_not_matter")) + def testInvalidateCachesWithMultipleZipimports(self): + packdir = TESTPACK + os.sep + packdir2 = packdir + TESTPACK2 + os.sep + files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc), + packdir2 + "__init__" + pyc_ext: (NOW, test_pyc), + packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc), + "spam" + pyc_ext: (NOW, test_pyc)} + self.addCleanup(os_helper.unlink, TEMP_ZIP) + with ZipFile(TEMP_ZIP, "w") as z: + for name, (mtime, data) in files.items(): + zinfo = ZipInfo(name, time.localtime(mtime)) + zinfo.compress_type = self.compression + zinfo.comment = b"spam" + z.writestr(zinfo, data) + + zi = zipimport.zipimporter(TEMP_ZIP) + self.assertEqual(zi._get_files().keys(), files.keys()) + # Zipimporter for the same path. + zi2 = zipimport.zipimporter(TEMP_ZIP) + self.assertEqual(zi2._get_files().keys(), files.keys()) + # Add a new file to the ZIP archive to make the cache wrong. + newfile = {"spam2" + pyc_ext: (NOW, test_pyc)} + files.update(newfile) + with ZipFile(TEMP_ZIP, "a") as z: + for name, (mtime, data) in newfile.items(): + zinfo = ZipInfo(name, time.localtime(mtime)) + zinfo.compress_type = self.compression + zinfo.comment = b"spam" + z.writestr(zinfo, data) + # Invalidate the cache of the first zipimporter. + zi.invalidate_caches() + # Check that the second zipimporter detects the new file and isn't using a stale cache. + self.assertEqual(zi2._get_files().keys(), files.keys()) + spec = zi2.find_spec('spam2') + self.assertIsNotNone(spec) + self.assertIsInstance(spec.loader, zipimport.zipimporter) + def testZipImporterMethodsInSubDirectory(self): packdir = TESTPACK + os.sep packdir2 = packdir + TESTPACK2 + os.sep diff --git a/Lib/zipimport.py b/Lib/zipimport.py index a7333a4c4906de..5b9f614f02f7af 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -88,12 +88,8 @@ def __init__(self, path): raise ZipImportError('not a Zip file', path=path) break - try: - files = _zip_directory_cache[path] - except KeyError: - files = _read_directory(path) - _zip_directory_cache[path] = files - self._files = files + if path not in _zip_directory_cache: + _zip_directory_cache[path] = _read_directory(path) self.archive = path # a prefix directory following the ZIP file path. self.prefix = _bootstrap_external._path_join(*prefix[::-1]) @@ -152,7 +148,7 @@ def get_data(self, pathname): key = pathname[len(self.archive + path_sep):] try: - toc_entry = self._files[key] + toc_entry = self._get_files()[key] except KeyError: raise OSError(0, '', key) return _get_data(self.archive, toc_entry) @@ -189,7 +185,7 @@ def get_source(self, fullname): fullpath = f'{path}.py' try: - toc_entry = self._files[fullpath] + toc_entry = self._get_files()[fullpath] except KeyError: # we have the module, but no source return None @@ -268,14 +264,22 @@ def get_resource_reader(self, fullname): return ZipReader(self, fullname) - def invalidate_caches(self): - """Reload the file data of the archive path.""" + def _get_files(self): + """Return the files within the archive path.""" try: - self._files = _read_directory(self.archive) - _zip_directory_cache[self.archive] = self._files - except ZipImportError: - _zip_directory_cache.pop(self.archive, None) - self._files = {} + files = _zip_directory_cache[self.archive] + except KeyError: + try: + files = _zip_directory_cache[self.archive] = _read_directory(self.archive) + except ZipImportError: + files = {} + + return files + + + def invalidate_caches(self): + """Invalidates the cache of file data of the archive path.""" + _zip_directory_cache.pop(self.archive, None) def __repr__(self): @@ -305,15 +309,15 @@ def _is_dir(self, path): # of a namespace package. We test by seeing if the name, with an # appended path separator, exists. dirpath = path + path_sep - # If dirpath is present in self._files, we have a directory. - return dirpath in self._files + # If dirpath is present in self._get_files(), we have a directory. + return dirpath in self._get_files() # Return some information about a module. def _get_module_info(self, fullname): path = _get_module_path(self, fullname) for suffix, isbytecode, ispackage in _zip_searchorder: fullpath = path + suffix - if fullpath in self._files: + if fullpath in self._get_files(): return ispackage return None @@ -656,7 +660,7 @@ def _get_mtime_and_size_of_source(self, path): # strip 'c' or 'o' from *.py[co] assert path[-1:] in ('c', 'o') path = path[:-1] - toc_entry = self._files[path] + toc_entry = self._get_files()[path] # fetch the time stamp of the .py file for comparison # with an embedded pyc time stamp time = toc_entry[5] @@ -676,7 +680,7 @@ def _get_pyc_source(self, path): path = path[:-1] try: - toc_entry = self._files[path] + toc_entry = self._get_files()[path] except KeyError: return None else: @@ -692,7 +696,7 @@ def _get_module_code(self, fullname): fullpath = path + suffix _bootstrap._verbose_message('trying {}{}{}', self.archive, path_sep, fullpath, verbosity=2) try: - toc_entry = self._files[fullpath] + toc_entry = self._get_files()[fullpath] except KeyError: pass else: diff --git a/Misc/NEWS.d/next/Library/2023-04-03-08-09-40.gh-issue-103200.lq1Etz.rst b/Misc/NEWS.d/next/Library/2023-04-03-08-09-40.gh-issue-103200.lq1Etz.rst new file mode 100644 index 00000000000000..e264e0c81d3d90 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-03-08-09-40.gh-issue-103200.lq1Etz.rst @@ -0,0 +1 @@ +Fix cache repopulation semantics of zipimport.invalidate_caches(). The cache is now repopulated upon retrieving files with an invalid cache, not when the cache is invalidated. From d524b6f61f0b9fe4c359373185bf08bab423a218 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 8 Jul 2023 00:03:51 +0200 Subject: [PATCH 305/446] gh-106535: Document PEP 387 Soft Deprecation (#106536) Mark the optparse module as soft deprecated. --- Doc/glossary.rst | 15 +++++++++++++++ Doc/library/optparse.rst | 5 +++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 931360370d084c..a4650a6c3efa22 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1107,6 +1107,21 @@ Glossary when several are given, such as in ``variable_name[1:3:5]``. The bracket (subscript) notation uses :class:`slice` objects internally. + soft deprecated + A soft deprecation can be used when using an API which should no longer + be used to write new code, but it remains safe to continue using it in + existing code. The API remains documented and tested, but will not be + developed further (no enhancement). + + The main difference between a "soft" and a (regular) "hard" deprecation + is that the soft deprecation does not imply scheduling the removal of the + deprecated API. + + Another difference is that a soft deprecation does not issue a warning. + + See `PEP 387: Soft Deprecation + `_. + special method .. index:: pair: special; method diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst index 0cff3817452364..01177a04ab434d 100644 --- a/Doc/library/optparse.rst +++ b/Doc/library/optparse.rst @@ -11,8 +11,9 @@ **Source code:** :source:`Lib/optparse.py` .. deprecated:: 3.2 - The :mod:`optparse` module is deprecated and will not be developed further; - development will continue with the :mod:`argparse` module. + The :mod:`optparse` module is :term:`soft deprecated` and will not be + developed further; development will continue with the :mod:`argparse` + module. -------------- From 1b2938122d0bb97e802881321cf3ac87bb2bfaef Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 8 Jul 2023 00:50:51 +0200 Subject: [PATCH 306/446] gh-105373: Doc lists pending C API removals (#106537) --- Doc/whatsnew/3.13.rst | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 8f737c5935f67b..fbd34122ac5728 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -470,6 +470,7 @@ Deprecated * :c:func:`Py_GetPythonHome`: get :c:member:`PyConfig.home` or :envvar:`PYTHONHOME` environment variable instead. + Functions scheduled for removal in Python 3.15. (Contributed by Victor Stinner in :gh:`105145`.) * Deprecate the :c:func:`PyImport_ImportModuleNoBlock` function which is just @@ -612,3 +613,82 @@ Removed `__ can be used to get :c:func:`PyInterpreterState_Get()` on Python 3.8 and older. (Contributed by Victor Stinner in :gh:`106320`.) + +Pending Removal in Python 3.15 +------------------------------ + +* :c:func:`PyImport_ImportModuleNoBlock`: use :c:func:`PyImport_ImportModule`. +* :c:func:`PyWeakref_GET_OBJECT`: use :c:func:`PyWeakref_GetRef` instead. +* :c:func:`PyWeakref_GetObject`: use :c:func:`PyWeakref_GetRef` instead. +* :c:type:`!Py_UNICODE_WIDE` type: use ``wchar_t`` instead. +* :c:type:`Py_UNICODE` type: use ``wchar_t`` instead. +* Python initialization functions: + + * :c:func:`PySys_ResetWarnOptions`: clear :data:`sys.warnoptions` and + :data:`!warnings.filters` instead. + * :c:func:`Py_GetExecPrefix`: get :data:`sys.exec_prefix` instead. + * :c:func:`Py_GetPath`: get :data:`sys.path` instead. + * :c:func:`Py_GetPrefix`: get :data:`sys.prefix` instead. + * :c:func:`Py_GetProgramFullPath`: get :data:`sys.executable` instead. + * :c:func:`Py_GetProgramName`: get :data:`sys.executable` instead. + * :c:func:`Py_GetPythonHome`: get :c:member:`PyConfig.home` or + :envvar:`PYTHONHOME` environment variable instead. + +Pending Removal in Future Versions +---------------------------------- + +The following APIs were deprecated in earlier Python versions and will be +removed, although there is currently no date scheduled for their removal. + +* :const:`Py_TPFLAGS_HAVE_FINALIZE`: no needed since Python 3.8. +* :c:func:`PyErr_Fetch`: use :c:func:`PyErr_GetRaisedException`. +* :c:func:`PyErr_NormalizeException`: use :c:func:`PyErr_GetRaisedException`. +* :c:func:`PyErr_Restore`: use :c:func:`PyErr_SetRaisedException`. +* :c:func:`PyModule_GetFilename`: use :c:func:`PyModule_GetFilenameObject`. +* :c:func:`PyOS_AfterFork`: use :c:func:`PyOS_AfterFork_Child()`. +* :c:func:`PySlice_GetIndicesEx`. +* :c:func:`!PyUnicode_AsDecodedObject`. +* :c:func:`!PyUnicode_AsDecodedUnicode`. +* :c:func:`!PyUnicode_AsEncodedObject`. +* :c:func:`!PyUnicode_AsEncodedUnicode`. +* :c:func:`PyUnicode_READY`: not needed since Python 3.12. +* :c:func:`!_PyErr_ChainExceptions`. +* :c:member:`!PyBytesObject.ob_shash` member: + call :c:func:`PyObject_Hash` instead. +* :c:member:`!PyDictObject.ma_version_tag` member. +* Global configuration variables: + + * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` + * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` + * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` + * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` + * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` + * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` + * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` + * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` + * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` + * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` + * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` + * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` + * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` + * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` + and :c:member:`PyConfig.hash_seed` + * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` + * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` + * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` + * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) + + The :c:func:`Py_InitializeFromConfig` API should be used with + :c:type:`PyConfig` instead. + +* TLS API: + + * :c:func:`PyThread_create_key`: use :c:func:`PyThread_tss_alloc`. + * :c:func:`PyThread_delete_key`: use :c:func:`PyThread_tss_free`. + * :c:func:`PyThread_set_key_value`: use :c:func:`PyThread_tss_set`. + * :c:func:`PyThread_get_key_value`: use :c:func:`PyThread_tss_get`. + * :c:func:`PyThread_delete_key_value`: use :c:func:`PyThread_tss_delete`. + * :c:func:`PyThread_ReInitTLS`: no longer needed. From ffe70c4d1c85f07d9b92bf0673e715fdaa2526ed Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 8 Jul 2023 01:49:20 +0200 Subject: [PATCH 307/446] gh-105373: Remove C API global config vars in Python 3.14 (#106538) Schedule the removal of C API global configuration variables in Python 3.14. Announce the removal to help C extension maintainers to upgrade their code. --- Doc/c-api/init.rst | 32 +++++++++++------------ Doc/whatsnew/3.13.rst | 59 +++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 1dab0af2659b4e..e7b2937d38dcf9 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -87,7 +87,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-b` option. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_DebugFlag @@ -101,7 +101,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-d` option and the :envvar:`PYTHONDEBUG` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_DontWriteBytecodeFlag @@ -115,7 +115,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-B` option and the :envvar:`PYTHONDONTWRITEBYTECODE` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_FrozenFlag @@ -128,7 +128,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Private flag used by ``_freeze_module`` and ``frozenmain`` programs. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_HashRandomizationFlag @@ -143,7 +143,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. If the flag is non-zero, read the :envvar:`PYTHONHASHSEED` environment variable to initialize the secret hash seed. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_IgnoreEnvironmentFlag @@ -156,7 +156,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-E` and :option:`-I` options. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_InspectFlag @@ -171,7 +171,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-i` option and the :envvar:`PYTHONINSPECT` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_InteractiveFlag @@ -196,7 +196,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. .. versionadded:: 3.4 - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_LegacyWindowsFSEncodingFlag @@ -215,7 +215,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. .. availability:: Windows. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_LegacyWindowsStdioFlag @@ -233,7 +233,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. .. availability:: Windows. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_NoSiteFlag @@ -248,7 +248,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-S` option. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_NoUserSiteDirectory @@ -262,7 +262,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-s` and :option:`-I` options, and the :envvar:`PYTHONNOUSERSITE` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_OptimizeFlag @@ -273,7 +273,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-O` option and the :envvar:`PYTHONOPTIMIZE` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_QuietFlag @@ -287,7 +287,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. .. versionadded:: 3.2 - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_UnbufferedStdioFlag @@ -300,7 +300,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-u` option and the :envvar:`PYTHONUNBUFFERED` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 .. c:var:: int Py_VerboseFlag @@ -316,7 +316,7 @@ to 1 and ``-bb`` sets :c:data:`Py_BytesWarningFlag` to 2. Set by the :option:`-v` option and the :envvar:`PYTHONVERBOSE` environment variable. - .. deprecated:: 3.12 + .. deprecated-removed:: 3.12 3.14 Initializing and finalizing the interpreter diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index fbd34122ac5728..b376f846b725e1 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -614,6 +614,37 @@ Removed :c:func:`PyInterpreterState_Get()` on Python 3.8 and older. (Contributed by Victor Stinner in :gh:`106320`.) +Pending Removal in Python 3.14 +------------------------------ + +* Global configuration variables: + + * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` + * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` + * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` + * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` + * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` + * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` + * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` + * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` + * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` + * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` + * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` + * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` + * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` + * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` + and :c:member:`PyConfig.hash_seed` + * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` + * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` + * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` + * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) + + The :c:func:`Py_InitializeFromConfig` API should be used with + :c:type:`PyConfig` instead. + Pending Removal in Python 3.15 ------------------------------ @@ -656,34 +687,6 @@ removed, although there is currently no date scheduled for their removal. * :c:member:`!PyBytesObject.ob_shash` member: call :c:func:`PyObject_Hash` instead. * :c:member:`!PyDictObject.ma_version_tag` member. -* Global configuration variables: - - * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` - * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` - * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` - * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` - * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` - * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` - * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` - * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` - * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` - * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` - * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` - * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` - * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` - * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` - and :c:member:`PyConfig.hash_seed` - * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` - * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` - * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` - * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` - * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) - - The :c:func:`Py_InitializeFromConfig` API should be used with - :c:type:`PyConfig` instead. - * TLS API: * :c:func:`PyThread_create_key`: use :c:func:`PyThread_tss_alloc`. From 48d5d32b80efe506e087e9b5a3302bf8df54aef4 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 7 Jul 2023 21:50:09 -0700 Subject: [PATCH 308/446] Restore previous behavior of 'make regen-cases' (#106541) When running 'make regen-cases' just to check whether anything changed, it's annoying that even if nothing changes, the output files are touched, causing an expensiv rebuild of _bootstrap_python and anything it creates. So use consistently for all output files. --- Makefile.pre.in | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 41623bd2f1da7f..073b4bcc271ffc 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1544,7 +1544,18 @@ regen-opcode-targets: regen-cases: # Regenerate various files from Python/bytecodes.c PYTHONPATH=$(srcdir)/Tools/cases_generator \ - $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/generate_cases.py -l + $(PYTHON_FOR_REGEN) \ + $(srcdir)/Tools/cases_generator/generate_cases.py \ + --emit-line-directives \ + -o $(srcdir)/Python/generated_cases.c.h.new \ + -m $(srcdir)/Python/opcode_metadata.h.new \ + -e $(srcdir)/Python/executor_cases.c.h.new \ + -p $(srcdir)/Lib/_opcode_metadata.py.new \ + $(srcdir)/Python/bytecodes.c + $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new + $(UPDATE_FILE) $(srcdir)/Python/opcode_metadata.h $(srcdir)/Python/opcode_metadata.h.new + $(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new + $(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new Python/compile.o: $(srcdir)/Python/opcode_metadata.h From 1c9e4934621627fbbfeada8d9dd87ecba4e446b0 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Sat, 8 Jul 2023 15:44:24 +0800 Subject: [PATCH 309/446] gh-106078: Move static objects related to `CONTEXTVAR` to the decimal module global state (#106395) Co-authored-by: Erlend E. Aasland --- Modules/_decimal/_decimal.c | 60 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 6da5095b91018a..7e1809cfb98b29 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,8 @@ #include "docstrings.h" +struct PyDecContextObject; + typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; @@ -50,6 +52,15 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; +#ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + struct PyDecContextObject *cached_context; +#else + PyObject *current_context_var; +#endif + /* Template for creating new thread contexts, calling Context() without * arguments and initializing the module_context on first access. */ PyObject *default_context_template; @@ -104,7 +115,7 @@ typedef struct { uint32_t *flags; } PyDecSignalDictObject; -typedef struct { +typedef struct PyDecContextObject { PyObject_HEAD mpd_context_t ctx; PyObject *traps; @@ -119,7 +130,6 @@ typedef struct { PyObject *global; } PyDecContextManagerObject; - #undef MPD #undef CTX #define PyDec_CheckExact(st, v) Py_IS_TYPE(v, (st)->PyDec_Type) @@ -145,16 +155,6 @@ incr_false(void) return Py_NewRef(Py_False); } - -#ifndef WITH_DECIMAL_CONTEXTVAR -/* Key for thread state dictionary */ -static PyObject *tls_context_key = NULL; -/* Invariant: NULL or the most recently accessed thread local context */ -static PyDecContextObject *cached_context = NULL; -#else -static PyObject *current_context_var = NULL; -#endif - /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) @@ -1565,7 +1565,8 @@ current_context_from_dict(void) return NULL; } - PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); + PyObject *tl_context; + tl_context = PyDict_GetItemWithError(dict, modstate->tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ CONTEXT_CHECK(modstate, tl_context); @@ -1576,13 +1577,13 @@ current_context_from_dict(void) } /* Set up a new thread local context. */ - tl_context = context_copy(state->default_context_template, NULL); + tl_context = context_copy(modstate->default_context_template, NULL); if (tl_context == NULL) { return NULL; } CTX(tl_context)->status = 0; - if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + if (PyDict_SetItem(dict, modstate->tls_context_key, tl_context) < 0) { Py_DECREF(tl_context); return NULL; } @@ -1591,8 +1592,8 @@ current_context_from_dict(void) /* Cache the context of the current thread, assuming that it * will be accessed several times before a thread switch. */ - cached_context = (PyDecContextObject *)tl_context; - cached_context->tstate = tstate; + modstate->cached_context = (PyDecContextObject *)tl_context; + modstate->cached_context->tstate = tstate; /* Borrowed reference with refcount==1 */ return tl_context; @@ -1603,8 +1604,9 @@ static PyObject * current_context(void) { PyThreadState *tstate = _PyThreadState_GET(); - if (cached_context && cached_context->tstate == tstate) { - return (PyObject *)cached_context; + decimal_state *modstate = GLOBAL_STATE(); + if (modstate->cached_context && modstate->cached_context->tstate == tstate) { + return (PyObject *)(modstate->cached_context); } return current_context_from_dict(); @@ -1662,8 +1664,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - cached_context = NULL; - if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + state->cached_context = NULL; + if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) { Py_DECREF(v); return NULL; } @@ -1682,7 +1684,7 @@ init_current_context(void) } CTX(tl_context)->status = 0; - PyObject *tok = PyContextVar_Set(current_context_var, tl_context); + PyObject *tok = PyContextVar_Set(state->current_context_var, tl_context); if (tok == NULL) { Py_DECREF(tl_context); return NULL; @@ -1696,7 +1698,8 @@ static inline PyObject * current_context(void) { PyObject *tl_context; - if (PyContextVar_Get(current_context_var, NULL, &tl_context) < 0) { + decimal_state *state = GLOBAL_STATE(); + if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) { return NULL; } @@ -1744,7 +1747,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - PyObject *tok = PyContextVar_Set(current_context_var, v); + PyObject *tok = PyContextVar_Set(state->current_context_var, v); Py_DECREF(v); if (tok == NULL) { return NULL; @@ -5987,10 +5990,11 @@ PyInit__decimal(void) Py_NewRef(state->default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR - ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + ASSIGN_PTR(state->tls_context_key, + PyUnicode_FromString("___DECIMAL_CTX__")); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); #else - ASSIGN_PTR(current_context_var, PyContextVar_New("decimal_context", NULL)); + ASSIGN_PTR(state->current_context_var, PyContextVar_New("decimal_context", NULL)); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); #endif CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); @@ -6049,9 +6053,9 @@ PyInit__decimal(void) Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR - Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->tls_context_key); /* GCOV_NOT_REACHED */ #else - Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->current_context_var); /* GCOV_NOT_REACHED */ #endif Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index ad3d9b6513d69c..12f91726b2d2f7 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -422,7 +422,6 @@ Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - global_state - -Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - From 2ef1dc37f02b08536b677dd23ec51541a60effd7 Mon Sep 17 00:00:00 2001 From: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> Date: Sat, 8 Jul 2023 10:47:01 +0300 Subject: [PATCH 310/446] gh-106524: Fix a crash in _sre.template() (GH-106525) Some items remained uninitialized if _sre.template() was called with invalid indices. Then attempt to clear them in the destructor led to dereferencing of uninitialized pointer. --- Lib/test/test_re.py | 10 ++++++++++ .../2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst | 1 + Modules/_sre/sre.c | 2 ++ 3 files changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index e4d14356402db7..8f26d0aacf4eee 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2418,6 +2418,16 @@ def test_regression_gh94675(self): p.terminate() p.join() + def test_sre_template_invalid_group_index(self): + # see gh-106524 + import _sre + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", -1, ""]) + self.assertIn("invalid template", str(cm.exception)) + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", (), ""]) + self.assertIn("an integer is required", str(cm.exception)) + def get_debug_out(pat): with captured_stdout() as out: diff --git a/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst b/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst new file mode 100644 index 00000000000000..f3fd070e391a66 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-17-44-03.gh-issue-106524.XkBV8h.rst @@ -0,0 +1 @@ +Fix crash in :func:`!_sre.template` with templates containing invalid group indices. diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 3f11916f9e1726..98602b4c1eaaf1 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -1544,10 +1544,12 @@ _sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template) for (Py_ssize_t i = 0; i < n; i++) { Py_ssize_t index = PyLong_AsSsize_t(PyList_GET_ITEM(template, 2*i+1)); if (index == -1 && PyErr_Occurred()) { + Py_SET_SIZE(self, i); Py_DECREF(self); return NULL; } if (index < 0) { + Py_SET_SIZE(self, i); goto bad_template; } self->items[i].index = index; From 69a39bd9ad52241ca0e9a1926b4536c73017d067 Mon Sep 17 00:00:00 2001 From: Radislav Chugunov <52372310+chgnrdv@users.noreply.github.com> Date: Sat, 8 Jul 2023 11:44:50 +0300 Subject: [PATCH 311/446] gh-105873: Make `_xxsubinterpreters` use exception type name in shared exception (#105874) --- Lib/test/test__xxsubinterpreters.py | 4 ++-- Lib/test/test_importlib/test_util.py | 2 +- Modules/_xxsubinterpretersmodule.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 1ee18774d17209..ac2280eb7090e9 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -731,10 +731,10 @@ def assert_run_failed(self, exctype, msg=None): yield if msg is None: self.assertEqual(str(caught.exception).split(':')[0], - str(exctype)) + exctype.__name__) else: self.assertEqual(str(caught.exception), - "{}: {}".format(exctype, msg)) + "{}: {}".format(exctype.__name__, msg)) def test_invalid_syntax(self): with self.assert_run_failed(SyntaxError): diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index e967adc9451c81..5da72a21f586ee 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -655,7 +655,7 @@ def test_magic_number(self): @unittest.skipIf(_interpreters is None, 'subinterpreters required') class IncompatibleExtensionModuleRestrictionsTests(unittest.TestCase): - ERROR = re.compile("^: module (.*) does not support loading in subinterpreters") + ERROR = re.compile("^ImportError: module (.*) does not support loading in subinterpreters") def run_with_own_gil(self, script): interpid = _interpreters.create(isolated=True) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 40dea170fd1f8b..d2e0593872c5f0 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -273,7 +273,7 @@ _sharedexception_bind(PyObject *exc, _sharedexception *sharedexc) assert(exc != NULL); const char *failure = NULL; - PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc)); + PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name); if (nameobj == NULL) { failure = "unable to format exception type name"; goto error; From ec7180bd1b3c156d4484e8e6babc5ecb707420e3 Mon Sep 17 00:00:00 2001 From: Owain Davies <116417456+OTheDev@users.noreply.github.com> Date: Sat, 8 Jul 2023 15:48:33 +0700 Subject: [PATCH 312/446] gh-101880: add link to object.__hash__() in hash() builtin documentation (#101883) --- Doc/library/functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 9b9731e9189853..d8091f0b093aab 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -794,7 +794,7 @@ are always available. They are listed here in alphabetical order. For objects with custom :meth:`__hash__` methods, note that :func:`hash` truncates the return value based on the bit width of the host machine. - See :meth:`__hash__` for details. + See :meth:`__hash__ ` for details. .. function:: help() help(request) From 74ec02e9490d8aa086aa9ad9d1d34d2ad999b5af Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 8 Jul 2023 14:31:25 +0300 Subject: [PATCH 313/446] gh-106510: Fix DEBUG output for atomic group (GH-106511) --- Lib/re/_parser.py | 4 +++- Lib/test/test_re.py | 5 ++++- .../Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst diff --git a/Lib/re/_parser.py b/Lib/re/_parser.py index 6c8a4eccc0e0bb..22d10ab6e31d37 100644 --- a/Lib/re/_parser.py +++ b/Lib/re/_parser.py @@ -113,7 +113,6 @@ def __init__(self, state, data=None): self.width = None def dump(self, level=0): - nl = True seqtypes = (tuple, list) for op, av in self.data: print(level*" " + str(op), end='') @@ -135,6 +134,9 @@ def dump(self, level=0): if item_no: print(level*" " + "ELSE") item_no.dump(level+1) + elif isinstance(av, SubPattern): + print() + av.dump(level+1) elif isinstance(av, seqtypes): nl = False for a in av: diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 8f26d0aacf4eee..b1699b0f83dbdd 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2489,7 +2489,10 @@ def test_debug_flag(self): def test_atomic_group(self): self.assertEqual(get_debug_out(r'(?>ab?)'), '''\ -ATOMIC_GROUP [(LITERAL, 97), (MAX_REPEAT, (0, 1, [(LITERAL, 98)]))] +ATOMIC_GROUP + LITERAL 97 + MAX_REPEAT 0 1 + LITERAL 98 0. INFO 4 0b0 1 2 (to 5) 5: ATOMIC_GROUP 11 (to 17) diff --git a/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst b/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst new file mode 100644 index 00000000000000..e0646fa9bc0211 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-13-47-28.gh-issue-106510.9n5BdC.rst @@ -0,0 +1 @@ +Improve debug output for atomic groups in regular expressions. From b305c69d1085c9e6c6875559109f73b827cb6fe0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 8 Jul 2023 18:00:39 +0300 Subject: [PATCH 314/446] gh-106508: Improve debugging of the _sre module (GH-106509) Now the VERBOSE macro can control tracing on per-pattern basis: * 0 -- disabled * 1 -- only if the DEBUG flag set * 2 -- always --- Modules/_sre/sre.c | 32 +++++++++++++++++++++++++++----- Modules/_sre/sre.h | 1 + Modules/_sre/sre_lib.h | 3 +++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 98602b4c1eaaf1..f34a353432dec0 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -49,8 +49,14 @@ static const char copyright[] = #include -/* defining this one enables tracing */ -#undef VERBOSE +/* Defining this one controls tracing: + * 0 -- disabled + * 1 -- only if the DEBUG flag set + * 2 -- always + */ +#ifndef VERBOSE +# define VERBOSE 0 +#endif /* -------------------------------------------------------------------- */ @@ -70,10 +76,21 @@ static const char copyright[] = #define SRE_ERROR_MEMORY -9 /* out of memory */ #define SRE_ERROR_INTERRUPTED -10 /* signal handler raised exception */ -#if defined(VERBOSE) -#define TRACE(v) printf v +#if VERBOSE == 0 +# define INIT_TRACE(state) +# define TRACE(v) +#elif VERBOSE == 1 +# define INIT_TRACE(state) int _debug = (state)->debug +# define TRACE(v) do { \ + if (_debug) { \ + printf v; \ + } \ + } while (0) +#elif VERBOSE == 2 +# define INIT_TRACE(state) +# define TRACE(v) printf v #else -#define TRACE(v) +# error VERBOSE must be 0, 1 or 2 #endif /* -------------------------------------------------------------------- */ @@ -198,6 +215,7 @@ data_stack_dealloc(SRE_STATE* state) static int data_stack_grow(SRE_STATE* state, Py_ssize_t size) { + INIT_TRACE(state); Py_ssize_t minsize, cursize; minsize = state->data_stack_base+size; cursize = state->data_stack_size; @@ -449,6 +467,7 @@ state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, state->charsize = charsize; state->match_all = 0; state->must_advance = 0; + state->debug = ((pattern->flags & SRE_FLAG_DEBUG) != 0); state->beginning = ptr; @@ -641,6 +660,7 @@ _sre_SRE_Pattern_match_impl(PatternObject *self, PyTypeObject *cls, if (!state_init(&state, (PatternObject *)self, string, pos, endpos)) return NULL; + INIT_TRACE(&state); state.ptr = state.start; TRACE(("|%p|%p|MATCH\n", PatternObject_GetCode(self), state.ptr)); @@ -684,6 +704,7 @@ _sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyTypeObject *cls, if (!state_init(&state, self, string, pos, endpos)) return NULL; + INIT_TRACE(&state); state.ptr = state.start; TRACE(("|%p|%p|FULLMATCH\n", PatternObject_GetCode(self), state.ptr)); @@ -730,6 +751,7 @@ _sre_SRE_Pattern_search_impl(PatternObject *self, PyTypeObject *cls, if (!state_init(&state, self, string, pos, endpos)) return NULL; + INIT_TRACE(&state); TRACE(("|%p|%p|SEARCH\n", PatternObject_GetCode(self), state.ptr)); status = sre_search(&state, PatternObject_GetCode(self)); diff --git a/Modules/_sre/sre.h b/Modules/_sre/sre.h index d967d9ea04ba7a..f60078d6bb999b 100644 --- a/Modules/_sre/sre.h +++ b/Modules/_sre/sre.h @@ -84,6 +84,7 @@ typedef struct { int charsize; /* character size */ int match_all; int must_advance; + int debug; /* marks */ int lastmark; int lastindex; diff --git a/Modules/_sre/sre_lib.h b/Modules/_sre/sre_lib.h index fb4c18b63d643d..c1a774f69090b3 100644 --- a/Modules/_sre/sre_lib.h +++ b/Modules/_sre/sre_lib.h @@ -209,6 +209,7 @@ SRE(count)(SRE_STATE* state, const SRE_CODE* pattern, Py_ssize_t maxcount) const SRE_CHAR* ptr = (const SRE_CHAR *)state->ptr; const SRE_CHAR* end = (const SRE_CHAR *)state->end; Py_ssize_t i; + INIT_TRACE(state); /* adjust end */ if (maxcount < end - ptr && maxcount != SRE_MAXREPEAT) @@ -567,6 +568,7 @@ SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel) SRE(match_context)* ctx; SRE(match_context)* nextctx; + INIT_TRACE(state); TRACE(("|%p|%p|ENTER\n", pattern, state->ptr)); @@ -1639,6 +1641,7 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern) SRE_CODE* charset = NULL; SRE_CODE* overlap = NULL; int flags = 0; + INIT_TRACE(state); if (ptr > end) return 0; From da98ed0aa040791ef08b24befab697038c8c9fd5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 8 Jul 2023 17:51:45 +0200 Subject: [PATCH 315/446] gh-106535: Soft deprecate the getopt module (#105735) The getopt module exists since the initial revision of the Python source code (1990). The optparse module was added to Python 2.3. When Python 2.7 added the 3rd argparse module, the optparse module was soft deprecated. Soft deprecate the getopt module. --- Doc/library/getopt.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Doc/library/getopt.rst b/Doc/library/getopt.rst index 336deab28cb8a4..ada68b240143e8 100644 --- a/Doc/library/getopt.rst +++ b/Doc/library/getopt.rst @@ -7,18 +7,23 @@ **Source code:** :source:`Lib/getopt.py` +.. deprecated:: 3.13 + The :mod:`getopt` module is :term:`soft deprecated` and will not be + developed further; development will continue with the :mod:`argparse` + module. + .. note:: The :mod:`getopt` module is a parser for command line options whose API is - designed to be familiar to users of the C :c:func:`getopt` function. Users who - are unfamiliar with the C :c:func:`getopt` function or who would like to write + designed to be familiar to users of the C :c:func:`!getopt` function. Users who + are unfamiliar with the C :c:func:`!getopt` function or who would like to write less code and get better help and error messages should consider using the :mod:`argparse` module instead. -------------- This module helps scripts to parse the command line arguments in ``sys.argv``. -It supports the same conventions as the Unix :c:func:`getopt` function (including +It supports the same conventions as the Unix :c:func:`!getopt` function (including the special meanings of arguments of the form '``-``' and '``--``'). Long options similar to those supported by GNU software may be used as well via an optional third argument. @@ -33,11 +38,11 @@ exception: be parsed, without the leading reference to the running program. Typically, this means ``sys.argv[1:]``. *shortopts* is the string of option letters that the script wants to recognize, with options that require an argument followed by a - colon (``':'``; i.e., the same format that Unix :c:func:`getopt` uses). + colon (``':'``; i.e., the same format that Unix :c:func:`!getopt` uses). .. note:: - Unlike GNU :c:func:`getopt`, after a non-option argument, all further + Unlike GNU :c:func:`!getopt`, after a non-option argument, all further arguments are considered also non-options. This is similar to the way non-GNU Unix systems work. @@ -71,7 +76,7 @@ exception: non-option argument is encountered. If the first character of the option string is ``'+'``, or if the environment - variable :envvar:`POSIXLY_CORRECT` is set, then option processing stops as + variable :envvar:`!POSIXLY_CORRECT` is set, then option processing stops as soon as a non-option argument is encountered. @@ -81,9 +86,9 @@ exception: an option requiring an argument is given none. The argument to the exception is a string indicating the cause of the error. For long options, an argument given to an option which does not require one will also cause this exception to be - raised. The attributes :attr:`msg` and :attr:`opt` give the error message and + raised. The attributes :attr:`!msg` and :attr:`!opt` give the error message and related option; if there is no specific option to which the exception relates, - :attr:`opt` is an empty string. + :attr:`!opt` is an empty string. .. XXX deprecated? .. exception:: error From dcc028d92428bd57358a5028ada2a53fc79fc365 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 9 Jul 2023 10:32:50 +0200 Subject: [PATCH 316/446] gh-105376: Remove logging.warn() and LoggerAdapter.warn() (#106553) --- Doc/library/logging.rst | 8 ++++++++ Doc/whatsnew/3.13.rst | 9 +++++---- Lib/logging/__init__.py | 12 +----------- .../2023-06-06-15-32-44.gh-issue-105376.W4oDQp.rst | 9 +++++---- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index d7a389fa13d6a0..4e07eabd57f5e9 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -1015,6 +1015,10 @@ interchangeably. Attribute :attr:`manager` and method :meth:`_log` were added, which delegate to the underlying logger and allow adapters to be nested. +.. versionchanged:: 3.13 + Remove the undocumented ``warn()`` method which was an alias to the + ``warning()`` method. + Thread Safety ------------- @@ -1162,6 +1166,10 @@ functions. identical to ``warning``. As ``warn`` is deprecated, please do not use it - use ``warning`` instead. + .. versionchanged:: 3.13 + Remove the undocumented ``warn()`` function which was an alias to the + :func:`warning` function. + .. function:: error(msg, *args, **kwargs) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index b376f846b725e1..7a4ec5fd913033 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -348,10 +348,11 @@ Removed use ``locale.setlocale(locale.LC_ALL, "")`` instead. (Contributed by Victor Stinner in :gh:`104783`.) -* Remove the undocumented and untested ``logging.Logger.warn()`` method, - deprecated since Python 3.3, which was an alias to the - :meth:`logging.Logger.warning` method: use the :meth:`logging.Logger.warning` - method instead. +* :mod:`logging`: Remove undocumented and untested ``Logger.warn()`` and + ``LoggerAdapter.warn()`` methods and ``logging.warn()`` function. Deprecated + since Python 3.3, they were aliases to the :meth:`logging.Logger.warning` + method, :meth:`!logging.LoggerAdapter.warning` method and + :func:`logging.warning` function. (Contributed by Victor Stinner in :gh:`105376`.) * Remove *cafile*, *capath* and *cadefault* parameters of the diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index fe2039af0334a0..2a011b6d2ff15d 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -37,7 +37,7 @@ 'captureWarnings', 'critical', 'debug', 'disable', 'error', 'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass', 'info', 'log', 'makeLogRecord', 'setLoggerClass', 'shutdown', - 'warn', 'warning', 'getLogRecordFactory', 'setLogRecordFactory', + 'warning', 'getLogRecordFactory', 'setLogRecordFactory', 'lastResort', 'raiseExceptions', 'getLevelNamesMapping', 'getHandlerByName', 'getHandlerNames'] @@ -1928,11 +1928,6 @@ def warning(self, msg, *args, **kwargs): """ self.log(WARNING, msg, *args, **kwargs) - def warn(self, msg, *args, **kwargs): - warnings.warn("The 'warn' method is deprecated, " - "use 'warning' instead", DeprecationWarning, 2) - self.warning(msg, *args, **kwargs) - def error(self, msg, *args, **kwargs): """ Delegate an error call to the underlying logger. @@ -2206,11 +2201,6 @@ def warning(msg, *args, **kwargs): basicConfig() root.warning(msg, *args, **kwargs) -def warn(msg, *args, **kwargs): - warnings.warn("The 'warn' function is deprecated, " - "use 'warning' instead", DeprecationWarning, 2) - warning(msg, *args, **kwargs) - def info(msg, *args, **kwargs): """ Log a message with severity 'INFO' on the root logger. If the logger has diff --git a/Misc/NEWS.d/next/Library/2023-06-06-15-32-44.gh-issue-105376.W4oDQp.rst b/Misc/NEWS.d/next/Library/2023-06-06-15-32-44.gh-issue-105376.W4oDQp.rst index a7d3172ca4c642..2ed6b5e0a7ac0a 100644 --- a/Misc/NEWS.d/next/Library/2023-06-06-15-32-44.gh-issue-105376.W4oDQp.rst +++ b/Misc/NEWS.d/next/Library/2023-06-06-15-32-44.gh-issue-105376.W4oDQp.rst @@ -1,4 +1,5 @@ -Remove the undocumented and untested ``logging.Logger.warn()`` method, -deprecated since Python 3.3, which was an alias to the -:meth:`logging.Logger.warning` method: use the :meth:`logging.Logger.warning` -method instead. Patch by Victor Stinner. +:mod:`logging`: Remove undocumented and untested ``Logger.warn()`` and +``LoggerAdapter.warn()`` methods and ``logging.warn()`` function. Deprecated +since Python 3.3, they were aliases to the :meth:`logging.Logger.warning` +method, :meth:`!logging.LoggerAdapter.warning` method and +:func:`logging.warning` function. Patch by Victor Stinner. From 8cb6f9761e3c1cff3210697e3670b57591bf2e7a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 9 Jul 2023 12:48:36 +0300 Subject: [PATCH 317/446] Move implementation specific RE tests to separate class (GH-106563) --- Lib/test/test_re.py | 135 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index b1699b0f83dbdd..a6f5af17d7d51b 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1046,33 +1046,6 @@ def test_ignore_case_range(self): def test_category(self): self.assertEqual(re.match(r"(\s)", " ").group(1), " ") - @cpython_only - def test_case_helpers(self): - import _sre - for i in range(128): - c = chr(i) - lo = ord(c.lower()) - self.assertEqual(_sre.ascii_tolower(i), lo) - self.assertEqual(_sre.unicode_tolower(i), lo) - iscased = c in string.ascii_letters - self.assertEqual(_sre.ascii_iscased(i), iscased) - self.assertEqual(_sre.unicode_iscased(i), iscased) - - for i in list(range(128, 0x1000)) + [0x10400, 0x10428]: - c = chr(i) - self.assertEqual(_sre.ascii_tolower(i), i) - if i != 0x0130: - self.assertEqual(_sre.unicode_tolower(i), ord(c.lower())) - iscased = c != c.lower() or c != c.upper() - self.assertFalse(_sre.ascii_iscased(i)) - self.assertEqual(_sre.unicode_iscased(i), - c != c.lower() or c != c.upper()) - - self.assertEqual(_sre.ascii_tolower(0x0130), 0x0130) - self.assertEqual(_sre.unicode_tolower(0x0130), ord('i')) - self.assertFalse(_sre.ascii_iscased(0x0130)) - self.assertTrue(_sre.unicode_iscased(0x0130)) - def test_not_literal(self): self.assertEqual(re.search(r"\s([^a])", " b").group(1), "b") self.assertEqual(re.search(r"\s([^a]*)", " bb").group(1), "bb") @@ -1770,20 +1743,6 @@ def test_bug_6509(self): pat = re.compile(b'..') self.assertEqual(pat.sub(lambda m: b'bytes', b'a5'), b'bytes') - def test_dealloc(self): - # issue 3299: check for segfault in debug build - import _sre - # the overflow limit is different on wide and narrow builds and it - # depends on the definition of SRE_CODE (see sre.h). - # 2**128 should be big enough to overflow on both. For smaller values - # a RuntimeError is raised instead of OverflowError. - long_overflow = 2**128 - self.assertRaises(TypeError, re.finditer, "a", {}) - with self.assertRaises(OverflowError): - _sre.compile("abc", 0, [long_overflow], 0, {}, ()) - with self.assertRaises(TypeError): - _sre.compile({}, 0, [], 0, [], []) - def test_search_dot_unicode(self): self.assertTrue(re.search("123.*-", '123abc-')) self.assertTrue(re.search("123.*-", '123\xe9-')) @@ -1841,21 +1800,6 @@ def test_repeat_minmax_overflow(self): self.assertRaises(OverflowError, re.compile, r".{%d,}?" % 2**128) self.assertRaises(OverflowError, re.compile, r".{%d,%d}" % (2**129, 2**128)) - @cpython_only - def test_repeat_minmax_overflow_maxrepeat(self): - try: - from _sre import MAXREPEAT - except ImportError: - self.skipTest('requires _sre.MAXREPEAT constant') - string = "x" * 100000 - self.assertIsNone(re.match(r".{%d}" % (MAXREPEAT - 1), string)) - self.assertEqual(re.match(r".{,%d}" % (MAXREPEAT - 1), string).span(), - (0, 100000)) - self.assertIsNone(re.match(r".{%d,}?" % (MAXREPEAT - 1), string)) - self.assertRaises(OverflowError, re.compile, r".{%d}" % MAXREPEAT) - self.assertRaises(OverflowError, re.compile, r".{,%d}" % MAXREPEAT) - self.assertRaises(OverflowError, re.compile, r".{%d,}?" % MAXREPEAT) - def test_backref_group_name_in_exception(self): # Issue 17341: Poor error message when compiling invalid regex self.checkPatternError('(?P=)', @@ -2418,16 +2362,6 @@ def test_regression_gh94675(self): p.terminate() p.join() - def test_sre_template_invalid_group_index(self): - # see gh-106524 - import _sre - with self.assertRaises(TypeError) as cm: - _sre.template("", ["", -1, ""]) - self.assertIn("invalid template", str(cm.exception)) - with self.assertRaises(TypeError) as cm: - _sre.template("", ["", (), ""]) - self.assertIn("an integer is required", str(cm.exception)) - def get_debug_out(pat): with captured_stdout() as out: @@ -2676,6 +2610,75 @@ def test_deprecated_modules(self): self.assertTrue(hasattr(mod, attr)) del sys.modules[name] + @cpython_only + def test_case_helpers(self): + import _sre + for i in range(128): + c = chr(i) + lo = ord(c.lower()) + self.assertEqual(_sre.ascii_tolower(i), lo) + self.assertEqual(_sre.unicode_tolower(i), lo) + iscased = c in string.ascii_letters + self.assertEqual(_sre.ascii_iscased(i), iscased) + self.assertEqual(_sre.unicode_iscased(i), iscased) + + for i in list(range(128, 0x1000)) + [0x10400, 0x10428]: + c = chr(i) + self.assertEqual(_sre.ascii_tolower(i), i) + if i != 0x0130: + self.assertEqual(_sre.unicode_tolower(i), ord(c.lower())) + iscased = c != c.lower() or c != c.upper() + self.assertFalse(_sre.ascii_iscased(i)) + self.assertEqual(_sre.unicode_iscased(i), + c != c.lower() or c != c.upper()) + + self.assertEqual(_sre.ascii_tolower(0x0130), 0x0130) + self.assertEqual(_sre.unicode_tolower(0x0130), ord('i')) + self.assertFalse(_sre.ascii_iscased(0x0130)) + self.assertTrue(_sre.unicode_iscased(0x0130)) + + @cpython_only + def test_dealloc(self): + # issue 3299: check for segfault in debug build + import _sre + # the overflow limit is different on wide and narrow builds and it + # depends on the definition of SRE_CODE (see sre.h). + # 2**128 should be big enough to overflow on both. For smaller values + # a RuntimeError is raised instead of OverflowError. + long_overflow = 2**128 + self.assertRaises(TypeError, re.finditer, "a", {}) + with self.assertRaises(OverflowError): + _sre.compile("abc", 0, [long_overflow], 0, {}, ()) + with self.assertRaises(TypeError): + _sre.compile({}, 0, [], 0, [], []) + + @cpython_only + def test_repeat_minmax_overflow_maxrepeat(self): + try: + from _sre import MAXREPEAT + except ImportError: + self.skipTest('requires _sre.MAXREPEAT constant') + string = "x" * 100000 + self.assertIsNone(re.match(r".{%d}" % (MAXREPEAT - 1), string)) + self.assertEqual(re.match(r".{,%d}" % (MAXREPEAT - 1), string).span(), + (0, 100000)) + self.assertIsNone(re.match(r".{%d,}?" % (MAXREPEAT - 1), string)) + self.assertRaises(OverflowError, re.compile, r".{%d}" % MAXREPEAT) + self.assertRaises(OverflowError, re.compile, r".{,%d}" % MAXREPEAT) + self.assertRaises(OverflowError, re.compile, r".{%d,}?" % MAXREPEAT) + + @cpython_only + def test_sre_template_invalid_group_index(self): + # see gh-106524 + import _sre + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", -1, ""]) + self.assertIn("invalid template", str(cm.exception)) + with self.assertRaises(TypeError) as cm: + _sre.template("", ["", (), ""]) + self.assertIn("an integer is required", str(cm.exception)) + + class ExternalTests(unittest.TestCase): def test_re_benchmarks(self): From d137c2cae28b79555433079d917c3e0614bdcd61 Mon Sep 17 00:00:00 2001 From: littlebutt's workshop Date: Sun, 9 Jul 2023 12:08:18 +0000 Subject: [PATCH 318/446] gh-104469: Convert_testcapi/vectorcall.c to use AC (gh-106557) --- Modules/_testcapi/clinic/vectorcall.c.h | 102 +++++++++++++++++++++++- Modules/_testcapi/vectorcall.c | 63 +++++++++------ 2 files changed, 140 insertions(+), 25 deletions(-) diff --git a/Modules/_testcapi/clinic/vectorcall.c.h b/Modules/_testcapi/clinic/vectorcall.c.h index 765afeda9b306c..728c0d382565a7 100644 --- a/Modules/_testcapi/clinic/vectorcall.c.h +++ b/Modules/_testcapi/clinic/vectorcall.c.h @@ -8,6 +8,106 @@ preserve #endif +PyDoc_STRVAR(_testcapi_pyobject_fastcalldict__doc__, +"pyobject_fastcalldict($module, func, func_args, kwargs, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_PYOBJECT_FASTCALLDICT_METHODDEF \ + {"pyobject_fastcalldict", _PyCFunction_CAST(_testcapi_pyobject_fastcalldict), METH_FASTCALL, _testcapi_pyobject_fastcalldict__doc__}, + +static PyObject * +_testcapi_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwargs); + +static PyObject * +_testcapi_pyobject_fastcalldict(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *func_args; + PyObject *__clinic_kwargs; + + if (!_PyArg_CheckPositional("pyobject_fastcalldict", nargs, 3, 3)) { + goto exit; + } + func = args[0]; + func_args = args[1]; + __clinic_kwargs = args[2]; + return_value = _testcapi_pyobject_fastcalldict_impl(module, func, func_args, __clinic_kwargs); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_pyobject_vectorcall__doc__, +"pyobject_vectorcall($module, func, func_args, kwnames, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_PYOBJECT_VECTORCALL_METHODDEF \ + {"pyobject_vectorcall", _PyCFunction_CAST(_testcapi_pyobject_vectorcall), METH_FASTCALL, _testcapi_pyobject_vectorcall__doc__}, + +static PyObject * +_testcapi_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwnames); + +static PyObject * +_testcapi_pyobject_vectorcall(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *func_args; + PyObject *__clinic_kwnames; + + if (!_PyArg_CheckPositional("pyobject_vectorcall", nargs, 3, 3)) { + goto exit; + } + func = args[0]; + func_args = args[1]; + __clinic_kwnames = args[2]; + return_value = _testcapi_pyobject_vectorcall_impl(module, func, func_args, __clinic_kwnames); + +exit: + return return_value; +} + +PyDoc_STRVAR(_testcapi_pyvectorcall_call__doc__, +"pyvectorcall_call($module, func, argstuple, kwargs=, /)\n" +"--\n" +"\n"); + +#define _TESTCAPI_PYVECTORCALL_CALL_METHODDEF \ + {"pyvectorcall_call", _PyCFunction_CAST(_testcapi_pyvectorcall_call), METH_FASTCALL, _testcapi_pyvectorcall_call__doc__}, + +static PyObject * +_testcapi_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs); + +static PyObject * +_testcapi_pyvectorcall_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *func; + PyObject *argstuple; + PyObject *__clinic_kwargs = NULL; + + if (!_PyArg_CheckPositional("pyvectorcall_call", nargs, 2, 3)) { + goto exit; + } + func = args[0]; + argstuple = args[1]; + if (nargs < 3) { + goto skip_optional; + } + __clinic_kwargs = args[2]; +skip_optional: + return_value = _testcapi_pyvectorcall_call_impl(module, func, argstuple, __clinic_kwargs); + +exit: + return return_value; +} + PyDoc_STRVAR(_testcapi_VectorCallClass_set_vectorcall__doc__, "set_vectorcall($self, type, /)\n" "--\n" @@ -110,4 +210,4 @@ _testcapi_has_vectorcall_flag(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=609569aa9942584f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=beaf6beac3d13c25 input=a9049054013a1b77]*/ diff --git a/Modules/_testcapi/vectorcall.c b/Modules/_testcapi/vectorcall.c index 4935fd1b6a7ba3..5ee468bd28c853 100644 --- a/Modules/_testcapi/vectorcall.c +++ b/Modules/_testcapi/vectorcall.c @@ -4,6 +4,10 @@ #include "structmember.h" // PyMemberDef #include // offsetof +/*[clinic input] +module _testcapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/ /* Test PEP 590 - Vectorcall */ @@ -25,18 +29,22 @@ fastcall_args(PyObject *args, PyObject ***stack, Py_ssize_t *nargs) return 0; } +/*[clinic input] +_testcapi.pyobject_fastcalldict + func: object + func_args: object + kwargs: object + / +[clinic start generated code]*/ static PyObject * -test_pyobject_fastcalldict(PyObject *self, PyObject *args) +_testcapi_pyobject_fastcalldict_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwargs) +/*[clinic end generated code: output=35902ece94de4418 input=b9c0196ca7d5f9e4]*/ { - PyObject *func, *func_args, *kwargs; PyObject **stack; Py_ssize_t nargs; - if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwargs)) { - return NULL; - } - if (fastcall_args(func_args, &stack, &nargs) < 0) { return NULL; } @@ -52,17 +60,22 @@ test_pyobject_fastcalldict(PyObject *self, PyObject *args) return PyObject_VectorcallDict(func, stack, nargs, kwargs); } +/*[clinic input] +_testcapi.pyobject_vectorcall + func: object + func_args: object + kwnames: object + / +[clinic start generated code]*/ + static PyObject * -test_pyobject_vectorcall(PyObject *self, PyObject *args) +_testcapi_pyobject_vectorcall_impl(PyObject *module, PyObject *func, + PyObject *func_args, PyObject *kwnames) +/*[clinic end generated code: output=ff77245bc6afe0d8 input=a0668dfef625764c]*/ { - PyObject *func, *func_args, *kwnames = NULL; PyObject **stack; Py_ssize_t nargs, nkw; - if (!PyArg_ParseTuple(args, "OOO", &func, &func_args, &kwnames)) { - return NULL; - } - if (fastcall_args(func_args, &stack, &nargs) < 0) { return NULL; } @@ -103,17 +116,19 @@ function_setvectorcall(PyObject *self, PyObject *func) Py_RETURN_NONE; } +/*[clinic input] +_testcapi.pyvectorcall_call + func: object + argstuple: object + kwargs: object = NULL + / +[clinic start generated code]*/ + static PyObject * -test_pyvectorcall_call(PyObject *self, PyObject *args) +_testcapi_pyvectorcall_call_impl(PyObject *module, PyObject *func, + PyObject *argstuple, PyObject *kwargs) +/*[clinic end generated code: output=809046fe78511306 input=4376ee7cabd698ce]*/ { - PyObject *func; - PyObject *argstuple; - PyObject *kwargs = NULL; - - if (!PyArg_ParseTuple(args, "OO|O", &func, &argstuple, &kwargs)) { - return NULL; - } - if (!PyTuple_Check(argstuple)) { PyErr_SetString(PyExc_TypeError, "args must be a tuple"); return NULL; @@ -242,10 +257,10 @@ _testcapi_has_vectorcall_flag_impl(PyObject *module, PyTypeObject *type) } static PyMethodDef TestMethods[] = { - {"pyobject_fastcalldict", test_pyobject_fastcalldict, METH_VARARGS}, - {"pyobject_vectorcall", test_pyobject_vectorcall, METH_VARARGS}, + _TESTCAPI_PYOBJECT_FASTCALLDICT_METHODDEF + _TESTCAPI_PYOBJECT_VECTORCALL_METHODDEF {"function_setvectorcall", function_setvectorcall, METH_O}, - {"pyvectorcall_call", test_pyvectorcall_call, METH_VARARGS}, + _TESTCAPI_PYVECTORCALL_CALL_METHODDEF _TESTCAPI_MAKE_VECTORCALL_CLASS_METHODDEF _TESTCAPI_HAS_VECTORCALL_FLAG_METHODDEF {NULL}, From 93d292c2b3f8e85ef562c37f59678c639b9b8fcb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 9 Jul 2023 15:27:03 +0300 Subject: [PATCH 319/446] gh-106303: Use _PyObject_LookupAttr() instead of PyObject_GetAttr() (GH-106304) It simplifies and speed up the code. --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + Include/internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 3 +++ Objects/funcobject.c | 15 +++++---------- Python/ceval.c | 16 ++++++---------- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index f85207b4bde292..6d50ffd0a02f1f 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -668,6 +668,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__lshift__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__lt__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__main__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__match_args__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__matmul__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__missing__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__mod__)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 3c9c12202ba1b9..bb1fb13f342fc6 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -157,6 +157,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__lshift__) STRUCT_FOR_ID(__lt__) STRUCT_FOR_ID(__main__) + STRUCT_FOR_ID(__match_args__) STRUCT_FOR_ID(__matmul__) STRUCT_FOR_ID(__missing__) STRUCT_FOR_ID(__mod__) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 9a28368a124ce8..2d66647438b193 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -663,6 +663,7 @@ extern "C" { INIT_ID(__lshift__), \ INIT_ID(__lt__), \ INIT_ID(__main__), \ + INIT_ID(__match_args__), \ INIT_ID(__matmul__), \ INIT_ID(__missing__), \ INIT_ID(__mod__), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 9e13a9491b7da5..59f40075f93983 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -315,6 +315,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { string = &_Py_ID(__main__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); + string = &_Py_ID(__match_args__); + assert(_PyUnicode_CheckConsistency(string, 1)); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__matmul__); assert(_PyUnicode_CheckConsistency(string, 1)); _PyUnicode_InternInPlace(interp, &string); diff --git a/Objects/funcobject.c b/Objects/funcobject.c index f43e3a2787b846..a8a9ee2b9bad46 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -942,17 +942,12 @@ PyTypeObject PyFunction_Type = { static int functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name) { - PyObject *value = PyObject_GetAttr(wrapped, name); - if (value == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - return 0; - } - return -1; + PyObject *value; + int res = _PyObject_LookupAttr(wrapped, name, &value); + if (value != NULL) { + res = PyObject_SetAttr(wrapper, name, value); + Py_DECREF(value); } - - int res = PyObject_SetAttr(wrapper, name, value); - Py_DECREF(value); return res; } diff --git a/Python/ceval.c b/Python/ceval.c index 1b8650a650412d..da1135549a255c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -418,10 +418,8 @@ match_class_attr(PyThreadState *tstate, PyObject *subject, PyObject *type, } return NULL; } - PyObject *attr = PyObject_GetAttr(subject, name); - if (attr == NULL && _PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { - _PyErr_Clear(tstate); - } + PyObject *attr; + (void)_PyObject_LookupAttr(subject, name, &attr); return attr; } @@ -456,7 +454,9 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, // First, the positional subpatterns: if (nargs) { int match_self = 0; - match_args = PyObject_GetAttrString(type, "__match_args__"); + if (_PyObject_LookupAttr(type, &_Py_ID(__match_args__), &match_args) < 0) { + goto fail; + } if (match_args) { if (!PyTuple_CheckExact(match_args)) { const char *e = "%s.__match_args__ must be a tuple (got %s)"; @@ -466,8 +466,7 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, goto fail; } } - else if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { - _PyErr_Clear(tstate); + else { // _Py_TPFLAGS_MATCH_SELF is only acknowledged if the type does not // define __match_args__. This is natural behavior for subclasses: // it's as if __match_args__ is some "magic" value that is lost as @@ -476,9 +475,6 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, match_self = PyType_HasFeature((PyTypeObject*)type, _Py_TPFLAGS_MATCH_SELF); } - else { - goto fail; - } assert(PyTuple_CheckExact(match_args)); Py_ssize_t allowed = match_self ? 1 : PyTuple_GET_SIZE(match_args); if (allowed < nargs) { From 1e12c8cfa373e57aaec65a574e5e4932bbbc0d4f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 9 Jul 2023 17:26:26 +0200 Subject: [PATCH 320/446] gh-105373: Doc lists pending removals (#106540) --- Doc/whatsnew/3.13.rst | 299 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 296 insertions(+), 3 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 7a4ec5fd913033..a01fc3b34b6fe8 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -90,7 +90,7 @@ Improved Modules array ----- -* Add ``'w'`` type code that can be used for Unicode strings. +* Add ``'w'`` type code (``Py_UCS4``) that can be used for Unicode strings. It can be used instead of ``'u'`` type code, which is deprecated. (Contributed by Inada Naoki in :gh:`80480`.) @@ -146,11 +146,11 @@ Deprecated methods of the :class:`wave.Wave_read` and :class:`wave.Wave_write` classes. They will be removed in Python 3.15. (Contributed by Victor Stinner in :gh:`105096`.) -* Creating a :class:`typing.NamedTuple` class using keyword arguments to denote +* :mod:`typing`: Creating a :class:`typing.NamedTuple` class using keyword arguments to denote the fields (``NT = NamedTuple("NT", x=int, y=int)``) is deprecated, and will be disallowed in Python 3.15. Use the class-based syntax or the functional syntax instead. (Contributed by Alex Waygood in :gh:`105566`.) -* When using the functional syntax to create a :class:`typing.NamedTuple` +* :mod:`typing`: When using the functional syntax to create a :class:`typing.NamedTuple` class or a :class:`typing.TypedDict` class, failing to pass a value to the 'fields' parameter (``NT = NamedTuple("NT")`` or ``TD = TypedDict("TD")``) is deprecated. Passing ``None`` to the 'fields' parameter @@ -172,6 +172,297 @@ Deprecated Replace ``ctypes.SetPointerType(item_type, size)`` with ``item_type * size``. (Contributed by Victor Stinner in :gh:`105733`.) +Pending Removal in Python 3.14 +------------------------------ + +* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters + of :class:`!argparse.BooleanOptionalAction` are deprecated + and will be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`92248`.) + +* :mod:`ast`: The following features have been deprecated in documentation + since Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at + runtime when they are accessed or used, and will be removed in Python 3.14: + + * :class:`!ast.Num` + * :class:`!ast.Str` + * :class:`!ast.Bytes` + * :class:`!ast.NameConstant` + * :class:`!ast.Ellipsis` + + Use :class:`ast.Constant` instead. + (Contributed by Serhiy Storchaka in :gh:`90953`.) + +* :mod:`collections.abc`: Deprecated :class:`~collections.abc.ByteString`. + Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`. + For use in typing, prefer a union, like ``bytes | bytearray``, + or :class:`collections.abc.Buffer`. + (Contributed by Shantanu Jain in :gh:`91896`.) + +* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + +* :mod:`importlib`: ``__package__`` and ``__cached__`` will cease to be set or + taken into consideration by the import system (:gh:`97879`). + +* :mod:`importlib.abc` deprecated classes: + + * :class:`!importlib.abc.ResourceReader` + * :class:`!importlib.abc.Traversable` + * :class:`!importlib.abc.TraversableResources` + + Use :mod:`importlib.resources.abc` classes instead: + + * :class:`importlib.resources.abc.Traversable` + * :class:`importlib.resources.abc.TraversableResources` + + (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) + +* :mod:`itertools` had undocumented, inefficient, historically buggy, + and inconsistent support for copy, deepcopy, and pickle operations. + This will be removed in 3.14 for a significant reduction in code + volume and maintenance burden. + (Contributed by Raymond Hettinger in :gh:`101588`.) + +* :mod:`multiprocessing`: The default start method will change to a safer one on + Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently + the default (:gh:`84559`). Adding a runtime warning about this was deemed too + disruptive as the majority of code is not expected to care. Use the + :func:`~multiprocessing.get_context` or + :func:`~multiprocessing.set_start_method` APIs to explicitly specify when + your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`. + +* :mod:`pathlib`: :meth:`~pathlib.PurePath.is_relative_to`, + :meth:`~pathlib.PurePath.relative_to`: passing additional arguments is + deprecated. + +* :func:`pkgutil.find_loader` and :func:`pkgutil.get_loader` + now raise :exc:`DeprecationWarning`; + use :func:`importlib.util.find_spec` instead. + (Contributed by Nikita Sobolev in :gh:`97850`.) + +* :mod:`pty`: + + * ``master_open()``: use :func:`pty.openpty`. + * ``slave_open()``: use :func:`pty.openpty`. + +* :func:`shutil.rmtree` *onerror* parameter is deprecated in 3.12, + and will be removed in 3.14: use the *onexc* parameter instead. + +* :mod:`sqlite3`: + + * :data:`~sqlite3.version` and :data:`~sqlite3.version_info`. + + * :meth:`~sqlite3.Cursor.execute` and :meth:`~sqlite3.Cursor.executemany` + if :ref:`named placeholders ` are used and + *parameters* is a sequence instead of a :class:`dict`. + + * date and datetime adapter, date and timestamp converter: + see the :mod:`sqlite3` documentation for suggested replacement recipes. + +* :class:`types.CodeType`: Accessing ``co_lnotab`` was deprecated in :pep:`626` + since 3.10 and was planned to be removed in 3.12, + but it only got a proper :exc:`DeprecationWarning` in 3.12. + May be removed in 3.14. + (Contributed by Nikita Sobolev in :gh:`101866`.) + +* :mod:`typing`: :class:`~typing.ByteString`, deprecated since Python 3.9, + now causes a :exc:`DeprecationWarning` to be emitted when it is used. + +* :class:`!urllib.parse.Quoter`. + +* :mod:`xml.etree.ElementTree`: Testing the truth value of an + :class:`~xml.etree.ElementTree.Element` is deprecated and will raise an + exception in Python 3.14. + +Pending Removal in Python 3.15 +------------------------------ + +* :class:`typing.NamedTuple`: + + * The undocumented keyword argument syntax for creating NamedTuple classes + (``NT = NamedTuple("NT", x=int)``) is deprecated, and will be disallowed in + 3.15. Use the class-based syntax or the functional syntax instead. + + * When using the functional syntax to create a NamedTuple class, failing to + pass a value to the 'fields' parameter (``NT = NamedTuple("NT")``) is + deprecated. Passing ``None`` to the 'fields' parameter + (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be + disallowed in Python 3.15. To create a NamedTuple class with 0 fields, use + ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``. + +* :class:`typing.TypedDict`: When using the functional syntax to create a + TypedDict class, failing to pass a value to the 'fields' parameter (``TD = + TypedDict("TD")``) is deprecated. Passing ``None`` to the 'fields' parameter + (``TD = TypedDict("TD", None)``) is also deprecated. Both will be disallowed + in Python 3.15. To create a TypedDict class with 0 fields, use ``class + TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. + +* :mod:`wave`: Deprecate the ``getmark()``, ``setmark()`` and ``getmarkers()`` + methods of the :class:`wave.Wave_read` and :class:`wave.Wave_write` classes. + They will be removed in Python 3.15. + (Contributed by Victor Stinner in :gh:`105096`.) + +Pending Removal in Python 3.16 +------------------------------ + +* :class:`array.array` ``'u'`` type (``wchar_t``): + use the ``'w'`` type instead (``Py_UCS4``). + +Pending Removal in Future Versions +---------------------------------- + +The following APIs were deprecated in earlier Python versions and will be removed, +although there is currently no date scheduled for their removal. + +* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive + groups are deprecated. + +* :mod:`builtins`: + + * ``~bool``, bitwise inversion on bool. + * ``bool(NotImplemented)``. + * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)`` + signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead, + the single argument signature. + * Currently Python accepts numeric literals immediately followed by keywords, + for example ``0in x``, ``1or x``, ``0if 1else 2``. It allows confusing and + ambiguous expressions like ``[0x1for x in y]`` (which can be interpreted as + ``[0x1 for x in y]`` or ``[0x1f or x in y]``). A syntax warning is raised + if the numeric literal is immediately followed by one of keywords + :keyword:`and`, :keyword:`else`, :keyword:`for`, :keyword:`if`, + :keyword:`in`, :keyword:`is` and :keyword:`or`. In a future release it + will be changed to a syntax error. (:gh:`87999`) + * Support for ``__index__()`` and ``__int__()`` method returning non-int type: + these methods will be required to return an instance of a strict subclass of + :class:`int`. + * Support for ``__float__()`` method returning a strict subclass of + :class:`float`: these methods will be required to return an instance of + :class:`float`. + * Support for ``__complex__()`` method returning a strict subclass of + :class:`complex`: these methods will be required to return an instance of + :class:`complex`. + * Delegation of ``int()`` to ``__trunc__()`` method. + +* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are + deprecated and replaced by :data:`calendar.Month.JANUARY` and + :data:`calendar.Month.FEBRUARY`. + (Contributed by Prince Roshan in :gh:`103636`.) + +* :mod:`datetime`: + + * :meth:`~datetime.datetime.utcnow`: + use ``datetime.datetime.now(tz=datetime.UTC)``. + * :meth:`~datetime.datetime.utcfromtimestamp`: + use ``datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)``. + +* :mod:`gettext`: Plural value must be an integer. + +* :mod:`importlib`: + + * ``load_module()`` method: use ``exec_module()`` instead. + * :func:`~importlib.util.cache_from_source` *debug_override* parameter is + deprecated: use the *optimization* parameter instead. + +* :mod:`importlib.metadata`: + + * ``EntryPoints`` tuple interface. + * Implicit ``None`` on return values. + +* :mod:`importlib.resources`: First parameter to files is renamed to 'anchor'. +* :mod:`importlib.resources` deprecated methods: + + * ``contents()`` + * ``is_resource()`` + * ``open_binary()`` + * ``open_text()`` + * ``path()`` + * ``read_binary()`` + * ``read_text()`` + + Use ``files()`` instead. Refer to `importlib-resources: Migrating from Legacy + `_ + for migration advice. + +* :func:`locale.getdefaultlocale`: use :func:`locale.setlocale()`, + :func:`locale.getencoding()` and :func:`locale.getlocale()` instead + (:gh:`90817`) + +* :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use + BytesIO and binary mode instead. + +* :mod:`os`: Calling :func:`os.register_at_fork` in multi-threaded process. + +* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is + deprecated, use an exception instance. + +* :mod:`re`: bad character in group name. + +* :mod:`ssl` options and protocols: + + * :class:`ssl.SSLContext` without protocol argument is deprecated. + * :class:`ssl.SSLContext`: :meth:`~ssl.SSLContext.set_npn_protocols` and + :meth:`!~ssl.SSLContext.selected_npn_protocol` are deprecated: use ALPN + instead. + * ``ssl.OP_NO_SSL*`` options + * ``ssl.OP_NO_TLS*`` options + * ``ssl.PROTOCOL_SSLv3`` + * ``ssl.PROTOCOL_TLS`` + * ``ssl.PROTOCOL_TLSv1`` + * ``ssl.PROTOCOL_TLSv1_1`` + * ``ssl.PROTOCOL_TLSv1_2`` + * ``ssl.TLSVersion.SSLv3`` + * ``ssl.TLSVersion.TLSv1`` + * ``ssl.TLSVersion.TLSv1_1`` + +* :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` modules. + +* ``types.CodeType.co_lnotab``: use the ``co_lines`` attribute instead. + +* :class:`typing.Text` (:gh:`92332`). + +* :func:`sysconfig.is_python_build` *check_home* parameter is deprecated and + ignored. + +* :mod:`threading` methods: + + * :meth:`!threading.Condition.notifyAll`: use :meth:`~threading.Condition.notify_all`. + * :meth:`!threading.Event.isSet`: use :meth:`~threading.Event.is_set`. + * :meth:`!threading.Thread.isDaemon`, :meth:`threading.Thread.setDaemon`: + use :attr:`threading.Thread.daemon` attribute. + * :meth:`!threading.Thread.getName`, :meth:`threading.Thread.setName`: + use :attr:`threading.Thread.name` attribute. + * :meth:`!threading.currentThread`: use :meth:`threading.current_thread`. + * :meth:`!threading.activeCount`: use :meth:`threading.active_count`. + +* :class:`unittest.IsolatedAsyncioTestCase`: it is deprecated to return a value + that is not None from a test case. + +* :mod:`urllib.request`: :class:`~urllib.request.URLopener` and + :class:`~urllib.request.FancyURLopener` style of invoking requests is + deprecated. Use newer :func:`~urllib.request.urlopen` functions and methods. + +* :func:`!urllib.parse.to_bytes`. + +* :mod:`urllib.parse` deprecated functions: :func:`~urllib.parse.urlparse` instead + + * ``splitattr()`` + * ``splithost()`` + * ``splitnport()`` + * ``splitpasswd()`` + * ``splitport()`` + * ``splitquery()`` + * ``splittag()`` + * ``splittype()`` + * ``splituser()`` + * ``splitvalue()`` + +* :mod:`wsgiref`: ``SimpleHandler.stdout.write()`` should not do partial + writes. + +* :meth:`zipimport.zipimporter.load_module` is deprecated: + use :meth:`~zipimport.zipimporter.exec_module` instead. + Removed ======= @@ -618,6 +909,8 @@ Removed Pending Removal in Python 3.14 ------------------------------ +* Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable + bases using the C API. * Global configuration variables: * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` From ee46cb6aa959d891b0a480fea29f1eb991e0fad8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 9 Jul 2023 17:50:26 +0200 Subject: [PATCH 321/446] gh-105927: PyWeakref_GetRef() returns 1 on success (#106561) PyWeakref_GetRef() now returns 1 on success, and return 0 if the reference is dead. Co-authored-by: Serhiy Storchaka --- Doc/c-api/weakref.rst | 6 ++++-- Modules/_testcapimodule.c | 2 +- Objects/weakrefobject.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index 04781f78d23462..038f54a9751fd1 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -55,9 +55,11 @@ as much as it can. Get a :term:`strong reference` to the referenced object from a weak reference, *ref*, into *\*pobj*. - Return 0 on success. Raise an exception and return -1 on error. - If the referent is no longer live, set *\*pobj* to ``NULL`` and return 0. + * On success, set *\*pobj* to a new :term:`strong reference` to the + referenced object and return 1. + * If the reference is dead, set *\*pobj* to ``NULL`` and return 0. + * On error, raise an exception and return -1. .. versionadded:: 3.13 diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 2baf453f710267..50eaff9917fd17 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3376,7 +3376,7 @@ test_weakref_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) // test PyWeakref_GetRef(), reference is alive PyObject *ref = Py_True; // marker to check that value was set - assert(PyWeakref_GetRef(weakref, &ref) == 0); + assert(PyWeakref_GetRef(weakref, &ref) == 1); assert(ref == obj); assert(Py_REFCNT(obj) == (refcnt + 1)); Py_DECREF(ref); diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index bac3e79bb7c250..e9563729bf82ba 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -913,7 +913,7 @@ PyWeakref_GetRef(PyObject *ref, PyObject **pobj) return -1; } *pobj = _PyWeakref_GET_REF(ref); - return 0; + return (*pobj != NULL); } From ca8b55c7f54b38e264056148075a8061a7082013 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 9 Jul 2023 21:46:15 +0100 Subject: [PATCH 322/446] gh-106461: typing: Consolidate docs on `Callable` (#106462) --- Doc/library/typing.rst | 130 ++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 55 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 7ac1062eb26d7c..11af3ea3c9030a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -258,18 +258,21 @@ See :pep:`484` for more details. The performance of calling ``NewType`` has been restored to its level in Python 3.9. +.. _annotating-callables: -Callable -======== +Annotating callable objects +=========================== -Frameworks expecting callback functions of specific signatures might be -type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``. +Functions -- or other :term:`callable` objects -- can be annotated using +:class:`collections.abc.Callable` or :data:`typing.Callable`. +``Callable[[int], str]`` signifies a function that takes a single parameter +of type :class:`int` and returns a :class:`str`. For example: .. testcode:: - from collections.abc import Callable + from collections.abc import Callable, Awaitable def feeder(get_next_item: Callable[[], str]) -> None: ... # Body @@ -283,9 +286,49 @@ For example: callback: Callable[[str], Awaitable[None]] = on_update -It is possible to declare the return type of a callable without specifying -the call signature by substituting a literal ellipsis -for the list of arguments in the type hint: ``Callable[..., ReturnType]``. +The subscription syntax must always be used with exactly two values: the +argument list and the return type. The argument list must be a list of types, +a :class:`ParamSpec`, :data:`Concatenate`, or an ellipsis. The return type must +be a single type. + +If a literal ellipsis ``...`` is given as the argument list, it indicates that +a callable with any arbitrary parameter list would be acceptable: + +.. testcode:: + + def concat(x: str, y: str) -> str: + return x + y + + x: Callable[..., str] + x = str # OK + x = concat # Also OK + +``Callable`` cannot express complex signatures such as functions that take a +variadic number of arguments, :func:`overloaded functions `, or +functions that have keyword-only parameters. However, these signatures can be +expressed by defining a :class:`Protocol` class with a +:meth:`~object.__call__` method: + +.. testcode:: + + from collections.abc import Iterable + from typing import Protocol + + class Combiner(Protocol): + def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + + def batch_proc(data: Iterable[bytes], cb_results: Combiner) -> bytes: + for item in data: + ... + + def good_cb(*vals: bytes, maxlen: int | None = None) -> list[bytes]: + ... + def bad_cb(*vals: bytes, maxitems: int | None) -> list[bytes]: + ... + + batch_proc([], good_cb) # OK + batch_proc([], bad_cb) # Error! Argument 2 has incompatible type because of + # different name and kind in the callback Callables which take other callables as arguments may indicate that their parameter types are dependent on each other using :class:`ParamSpec`. @@ -1043,56 +1086,16 @@ These can be used as types in annotations. They all support subscription using Optional can now be written as ``X | None``. See :ref:`union type expressions`. -.. data:: Callable - - Deprecated alias to :class:`collections.abc.Callable`. - - ``Callable[[int], str]`` signifies a function that takes a single parameter - of type :class:`int` and returns a :class:`str`. - - The subscription syntax must always be used with exactly two - values: the argument list and the return type. The argument list - must be a list of types, a :class:`ParamSpec`, :data:`Concatenate`, - or an ellipsis. The return type must be a single type. - - There is no syntax to indicate optional or keyword arguments; - such function types are rarely used as callback types. - ``Callable[..., ReturnType]`` (literal ellipsis) can be used to - type hint a callable taking any number of arguments and returning - ``ReturnType``. A plain :data:`Callable` is equivalent to - ``Callable[..., Any]``, and in turn to - :class:`collections.abc.Callable`. - - Callables which take other callables as arguments may indicate that their - parameter types are dependent on each other using :class:`ParamSpec`. - Additionally, if that callable adds or removes arguments from other - callables, the :data:`Concatenate` operator may be used. They - take the form ``Callable[ParamSpecVariable, ReturnType]`` and - ``Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType]`` - respectively. - - .. deprecated:: 3.9 - :class:`collections.abc.Callable` now supports subscripting (``[]``). - See :pep:`585` and :ref:`types-genericalias`. - - .. versionchanged:: 3.10 - ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. - See :pep:`612` for more details. - - .. seealso:: - The documentation for :class:`ParamSpec` and :class:`Concatenate` provide - examples of usage with ``Callable``. - .. data:: Concatenate Special form for annotating higher-order functions. - ``Concatenate`` can be used in conjunction with :data:`Callable` and + ``Concatenate`` can be used in conjunction with :ref:`Callable ` and :class:`ParamSpec` to annotate a higher-order callable which adds, removes, or transforms parameters of another callable. Usage is in the form ``Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]``. ``Concatenate`` - is currently only valid when used as the first argument to a :data:`Callable`. + is currently only valid when used as the first argument to a :ref:`Callable `. The last parameter to ``Concatenate`` must be a :class:`ParamSpec` or ellipsis (``...``). @@ -1136,8 +1139,9 @@ These can be used as types in annotations. They all support subscription using .. seealso:: * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`ParamSpec` and :class:`Callable`. + ``ParamSpec`` and ``Concatenate``) + * :class:`ParamSpec` + * :ref:`annotating-callables` .. data:: Literal @@ -1893,8 +1897,9 @@ without the dedicated syntax, as documented below. .. seealso:: * :pep:`612` -- Parameter Specification Variables (the PEP which introduced - ``ParamSpec`` and ``Concatenate``). - * :class:`Callable` and :class:`Concatenate`. + ``ParamSpec`` and ``Concatenate``) + * :data:`Concatenate` + * :ref:`annotating-callables` .. data:: ParamSpecArgs .. data:: ParamSpecKwargs @@ -2179,7 +2184,7 @@ types. methods or attributes, not their type signatures or types. For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` - check against :data:`Callable`. However, the + check against :ref:`Callable `. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. @@ -3533,6 +3538,21 @@ Aliases to other ABCs in :mod:`collections.abc` :class:`collections.abc.Iterator` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`. +.. data:: Callable + + Deprecated alias to :class:`collections.abc.Callable`. + + See :ref:`annotating-callables` for details on how to use + :class:`collections.abc.Callable` and ``typing.Callable`` in type annotations. + + .. deprecated:: 3.9 + :class:`collections.abc.Callable` now supports subscripting (``[]``). + See :pep:`585` and :ref:`types-genericalias`. + + .. versionchanged:: 3.10 + ``Callable`` now supports :class:`ParamSpec` and :data:`Concatenate`. + See :pep:`612` for more details. + .. class:: Generator(Iterator[YieldType], Generic[YieldType, SendType, ReturnType]) Deprecated alias to :class:`collections.abc.Generator`. From 970982e03d34655df262e14a5efcfdc0bddc0add Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 10 Jul 2023 04:05:38 +0200 Subject: [PATCH 323/446] gh-105733: Fix ctypes What's New entry (#106576) --- Doc/whatsnew/3.13.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index a01fc3b34b6fe8..767e78bf2470a7 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -169,7 +169,7 @@ Deprecated * :mod:`ctypes`: Deprecate undocumented :func:`!ctypes.SetPointerType` and :func:`!ctypes.ARRAY` functions. - Replace ``ctypes.SetPointerType(item_type, size)`` with ``item_type * size``. + Replace ``ctypes.ARRAY(item_type, size)`` with ``item_type * size``. (Contributed by Victor Stinner in :gh:`105733`.) Pending Removal in Python 3.14 From dac1e364901d3668742e6eecc2ce63586330c11f Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sun, 9 Jul 2023 20:41:31 -0700 Subject: [PATCH 324/446] Clarify how topics.py gets created. (#106121) When changing docs, it was easy to find text in topics.py, and I wondered whether I was supposed to edit it. Thankfully, the top of the file says it's auto-generated, so I knew I didn't have to edit it. But I didn't know what started the auto-generation process. It's part of the release process, so I'll leave a note here for future editors. --- Doc/tools/extensions/pyspecific.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py index 795aeed1007a79..8d99b0bfa4f381 100644 --- a/Doc/tools/extensions/pyspecific.py +++ b/Doc/tools/extensions/pyspecific.py @@ -559,6 +559,7 @@ def finish(self): try: f.write('# -*- coding: utf-8 -*-\n'.encode('utf-8')) f.write(('# Autogenerated by Sphinx on %s\n' % asctime()).encode('utf-8')) + f.write('# as part of the release process.\n'.encode('utf-8')) f.write(('topics = ' + pformat(self.topics) + '\n').encode('utf-8')) finally: f.close() From 34c14147a2c52930b8b471905074509639e82d5b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 10 Jul 2023 12:52:36 +0300 Subject: [PATCH 325/446] gh-106487: Allow the 'count' argument of `str.replace` to be a keyword (#106488) --- Doc/library/stdtypes.rst | 9 ++-- Doc/whatsnew/3.13.rst | 3 +- Lib/test/string_tests.py | 6 +++ ...-07-06-22-46-05.gh-issue-106487.u3KfAD.rst | 2 + Objects/clinic/unicodeobject.c.h | 44 +++++++++++++++---- Objects/unicodeobject.c | 4 +- 6 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-06-22-46-05.gh-issue-106487.u3KfAD.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 0ac727e0df38b3..8e049d9645c0b6 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2014,11 +2014,14 @@ expression support in the :mod:`re` module). .. versionadded:: 3.9 -.. method:: str.replace(old, new[, count]) +.. method:: str.replace(old, new, count=-1) Return a copy of the string with all occurrences of substring *old* replaced by - *new*. If the optional argument *count* is given, only the first *count* - occurrences are replaced. + *new*. If *count* is given, only the first *count* occurrences are replaced. + If *count* is not specified or ``-1``, then all occurrences are replaced. + + .. versionchanged:: 3.13 + *count* is now supported as a keyword argument. .. method:: str.rfind(sub[, start[, end]]) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 767e78bf2470a7..8fc809deca139b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -76,7 +76,8 @@ New Features Other Language Changes ====================== - +* Allow the *count* argument of :meth:`str.replace` to be a keyword. + (Contributed by Hugo van Kemenade in :gh:`106487`.) New Modules =========== diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index a6ea2f378b37ac..8d210b198d248d 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -154,6 +154,12 @@ def test_count(self): self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i)) self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i)) + def test_count_keyword(self): + self.assertEqual('aa'.replace('a', 'b', 0), 'aa'.replace('a', 'b', count=0)) + self.assertEqual('aa'.replace('a', 'b', 1), 'aa'.replace('a', 'b', count=1)) + self.assertEqual('aa'.replace('a', 'b', 2), 'aa'.replace('a', 'b', count=2)) + self.assertEqual('aa'.replace('a', 'b', 3), 'aa'.replace('a', 'b', count=3)) + def test_find(self): self.checkequal(0, 'abcdefghiabc', 'find', 'abc') self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-06-22-46-05.gh-issue-106487.u3KfAD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-06-22-46-05.gh-issue-106487.u3KfAD.rst new file mode 100644 index 00000000000000..9e8100022bbd23 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-06-22-46-05.gh-issue-106487.u3KfAD.rst @@ -0,0 +1,2 @@ +Allow the *count* argument of :meth:`str.replace` to be a keyword. Patch by +Hugo van Kemenade. diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 70c7fe17501716..b9127e428f4c99 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -736,7 +736,7 @@ unicode_rstrip(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(unicode_replace__doc__, -"replace($self, old, new, count=-1, /)\n" +"replace($self, old, new, /, count=-1)\n" "--\n" "\n" "Return a copy with all occurrences of substring old replaced by new.\n" @@ -749,21 +749,49 @@ PyDoc_STRVAR(unicode_replace__doc__, "replaced."); #define UNICODE_REPLACE_METHODDEF \ - {"replace", _PyCFunction_CAST(unicode_replace), METH_FASTCALL, unicode_replace__doc__}, + {"replace", _PyCFunction_CAST(unicode_replace), METH_FASTCALL|METH_KEYWORDS, unicode_replace__doc__}, static PyObject * unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, Py_ssize_t count); static PyObject * -unicode_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +unicode_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(count), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"", "", "count", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "replace", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; PyObject *old; PyObject *new; Py_ssize_t count = -1; - if (!_PyArg_CheckPositional("replace", nargs, 2, 3)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf); + if (!args) { goto exit; } if (!PyUnicode_Check(args[0])) { @@ -776,8 +804,8 @@ unicode_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } new = args[1]; - if (nargs < 3) { - goto skip_optional; + if (!noptargs) { + goto skip_optional_pos; } { Py_ssize_t ival = -1; @@ -791,7 +819,7 @@ unicode_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } count = ival; } -skip_optional: +skip_optional_pos: return_value = unicode_replace_impl(self, old, new, count); exit: @@ -1476,4 +1504,4 @@ unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=0a71c4aeffdf0bc5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ee76a1b49cd4cbb3 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 12e379d0c7e6cd..f543c0a65b49f6 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12025,10 +12025,10 @@ str.replace as unicode_replace old: unicode new: unicode + / count: Py_ssize_t = -1 Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences. - / Return a copy with all occurrences of substring old replaced by new. @@ -12039,7 +12039,7 @@ replaced. static PyObject * unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, Py_ssize_t count) -/*[clinic end generated code: output=b63f1a8b5eebf448 input=147d12206276ebeb]*/ +/*[clinic end generated code: output=b63f1a8b5eebf448 input=3345c455d60a5499]*/ { return replace(self, old, new, count); } From 0c90e7561046a2deb358e6695148060a1c199b49 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 10 Jul 2023 11:40:35 +0100 Subject: [PATCH 326/446] GH-100288: Specialize LOAD_ATTR for simple class attributes. (#105990) * Add two more specializations of LOAD_ATTR. --- Include/internal/pycore_opcode.h | 40 +- Include/opcode.h | 52 +-- Lib/_opcode_metadata.py | 2 + ...-07-04-04-50-14.gh-issue-100288.yNQ1ez.rst | 3 + Python/bytecodes.c | 43 +- Python/executor_cases.c.h | 70 +-- Python/generated_cases.c.h | 398 ++++++++++-------- Python/opcode_metadata.h | 16 +- Python/opcode_targets.h | 36 +- Python/specialize.c | 35 +- 10 files changed, 405 insertions(+), 290 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-04-04-50-14.gh-issue-100288.yNQ1ez.rst diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index c7c2fdcc327884..d7f6b84e95c4f8 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -158,6 +158,8 @@ const uint8_t _PyOpcode_Deopt[256] = { [LOAD_ATTR_METHOD_NO_DICT] = LOAD_ATTR, [LOAD_ATTR_METHOD_WITH_VALUES] = LOAD_ATTR, [LOAD_ATTR_MODULE] = LOAD_ATTR, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = LOAD_ATTR, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = LOAD_ATTR, [LOAD_ATTR_PROPERTY] = LOAD_ATTR, [LOAD_ATTR_SLOT] = LOAD_ATTR, [LOAD_ATTR_WITH_HINT] = LOAD_ATTR, @@ -328,14 +330,14 @@ const char *const _PyOpcode_OpName[268] = { [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", - [COMPARE_OP_INT] = "COMPARE_OP_INT", + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "LOAD_ATTR_NONDESCRIPTOR_NO_DICT", [RETURN_VALUE] = "RETURN_VALUE", - [COMPARE_OP_STR] = "COMPARE_OP_STR", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [FOR_ITER_LIST] = "FOR_ITER_LIST", + [COMPARE_OP_INT] = "COMPARE_OP_INT", [LOAD_LOCALS] = "LOAD_LOCALS", - [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -358,9 +360,9 @@ const char *const _PyOpcode_OpName[268] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [FOR_ITER_GEN] = "FOR_ITER_GEN", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -379,11 +381,11 @@ const char *const _PyOpcode_OpName[268] = { [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", [RAISE_VARARGS] = "RAISE_VARARGS", [GET_AWAITABLE] = "GET_AWAITABLE", - [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [FOR_ITER_GEN] = "FOR_ITER_GEN", [BUILD_SLICE] = "BUILD_SLICE", [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", [MAKE_CELL] = "MAKE_CELL", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [LOAD_DEREF] = "LOAD_DEREF", [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", @@ -395,26 +397,26 @@ const char *const _PyOpcode_OpName[268] = { [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", [MAP_ADD] = "MAP_ADD", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [COPY_FREE_VARS] = "COPY_FREE_VARS", [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", [CONVERT_VALUE] = "CONVERT_VALUE", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", - [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [LOAD_FAST_LOAD_FAST] = "LOAD_FAST_LOAD_FAST", [STORE_FAST_LOAD_FAST] = "STORE_FAST_LOAD_FAST", [STORE_FAST_STORE_FAST] = "STORE_FAST_STORE_FAST", @@ -425,14 +427,14 @@ const char *const _PyOpcode_OpName[268] = { [LOAD_FROM_DICT_OR_GLOBALS] = "LOAD_FROM_DICT_OR_GLOBALS", [LOAD_FROM_DICT_OR_DEREF] = "LOAD_FROM_DICT_OR_DEREF", [SET_FUNCTION_ATTRIBUTE] = "SET_FUNCTION_ATTRIBUTE", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", [CALL_NO_KW_ALLOC_AND_ENTER_INIT] = "CALL_NO_KW_ALLOC_AND_ENTER_INIT", - [184] = "<184>", - [185] = "<185>", [186] = "<186>", [187] = "<187>", [188] = "<188>", @@ -519,8 +521,6 @@ const char *const _PyOpcode_OpName[268] = { #endif // NEED_OPCODE_TABLES #define EXTRA_CASES \ - case 184: \ - case 185: \ case 186: \ case 187: \ case 188: \ diff --git a/Include/opcode.h b/Include/opcode.h index 6b855bdd99dfa2..697520937d9055 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -201,31 +201,33 @@ extern "C" { #define LOAD_ATTR_METHOD_WITH_VALUES 78 #define LOAD_ATTR_METHOD_NO_DICT 79 #define LOAD_ATTR_METHOD_LAZY_DICT 80 -#define COMPARE_OP_FLOAT 81 -#define COMPARE_OP_INT 82 -#define COMPARE_OP_STR 84 -#define FOR_ITER_LIST 86 -#define FOR_ITER_TUPLE 88 -#define FOR_ITER_RANGE 111 -#define FOR_ITER_GEN 112 -#define CALL_BOUND_METHOD_EXACT_ARGS 113 -#define CALL_PY_EXACT_ARGS 132 -#define CALL_PY_WITH_DEFAULTS 136 -#define CALL_NO_KW_TYPE_1 148 -#define CALL_NO_KW_STR_1 153 -#define CALL_NO_KW_TUPLE_1 154 -#define CALL_BUILTIN_CLASS 155 -#define CALL_NO_KW_BUILTIN_O 159 -#define CALL_NO_KW_BUILTIN_FAST 160 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 161 -#define CALL_NO_KW_LEN 166 -#define CALL_NO_KW_ISINSTANCE 167 -#define CALL_NO_KW_LIST_APPEND 178 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 179 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 180 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 181 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 182 -#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 183 +#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 81 +#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 82 +#define COMPARE_OP_FLOAT 84 +#define COMPARE_OP_INT 86 +#define COMPARE_OP_STR 88 +#define FOR_ITER_LIST 111 +#define FOR_ITER_TUPLE 112 +#define FOR_ITER_RANGE 113 +#define FOR_ITER_GEN 132 +#define CALL_BOUND_METHOD_EXACT_ARGS 136 +#define CALL_PY_EXACT_ARGS 148 +#define CALL_PY_WITH_DEFAULTS 153 +#define CALL_NO_KW_TYPE_1 154 +#define CALL_NO_KW_STR_1 155 +#define CALL_NO_KW_TUPLE_1 159 +#define CALL_BUILTIN_CLASS 160 +#define CALL_NO_KW_BUILTIN_O 161 +#define CALL_NO_KW_BUILTIN_FAST 166 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 167 +#define CALL_NO_KW_LEN 178 +#define CALL_NO_KW_ISINSTANCE 179 +#define CALL_NO_KW_LIST_APPEND 180 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 181 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 182 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 183 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 184 +#define CALL_NO_KW_ALLOC_AND_ENTER_INIT 185 #define NB_ADD 0 #define NB_AND 1 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index b0fcd1a6b920f3..fd8ecdb5c980f3 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -63,6 +63,8 @@ "LOAD_ATTR_METHOD_WITH_VALUES", "LOAD_ATTR_METHOD_NO_DICT", "LOAD_ATTR_METHOD_LAZY_DICT", + "LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", + "LOAD_ATTR_NONDESCRIPTOR_NO_DICT", ], "COMPARE_OP": [ "COMPARE_OP_FLOAT", diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-04-50-14.gh-issue-100288.yNQ1ez.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-04-50-14.gh-issue-100288.yNQ1ez.rst new file mode 100644 index 00000000000000..faf43bd0c2f48e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-04-50-14.gh-issue-100288.yNQ1ez.rst @@ -0,0 +1,3 @@ +Specialize :opcode:`LOAD_ATTR` for non-descriptors on the class. Adds +:opcode:`LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES` and :opcode +`LOAD_ATTR_NONDESCRIPTOR_NO_DICT`. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 89b077ac428345..0848bbfd203ec4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1809,6 +1809,8 @@ dummy_func( LOAD_ATTR_METHOD_WITH_VALUES, LOAD_ATTR_METHOD_NO_DICT, LOAD_ATTR_METHOD_LAZY_DICT, + LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, + LOAD_ATTR_NONDESCRIPTOR_NO_DICT, }; inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) { @@ -2657,7 +2659,8 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } - inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (1), res)) { + assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -2673,10 +2676,10 @@ dummy_func( res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - assert(oparg & 1); } - inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) { + assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -2685,10 +2688,39 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - assert(oparg & 1); } - inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (0), res)) { + assert((oparg & 1) == 0); + PyTypeObject *self_cls = Py_TYPE(self); + assert(type_version != 0); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; + DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + keys_version, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + DECREF_INPUTS(); + res = Py_NewRef(descr); + } + + inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (0), res)) { + assert((oparg & 1) == 0); + PyTypeObject *self_cls = Py_TYPE(self); + assert(type_version != 0); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + DECREF_INPUTS(); + res = Py_NewRef(descr); + } + + inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) { + assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -2701,7 +2733,6 @@ dummy_func( assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - assert(oparg & 1); } inst(KW_NAMES, (--)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 32efeb099d9b3e..0ef752249ccb76 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1738,7 +1738,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2114 "Python/bytecodes.c" + #line 2116 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1760,7 +1760,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2129 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1786,7 +1786,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2148 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1809,12 +1809,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2163 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 1815 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2165 "Python/bytecodes.c" + #line 2167 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1820 "Python/executor_cases.c.h" STACK_SHRINK(1); @@ -1826,12 +1826,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2169 "Python/bytecodes.c" + #line 2171 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 1832 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2171 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 1838 "Python/executor_cases.c.h" @@ -1845,12 +1845,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2176 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 1851 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2178 "Python/bytecodes.c" + #line 2180 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1861,7 +1861,7 @@ #line 1862 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2186 "Python/bytecodes.c" + #line 2188 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1880,19 +1880,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2197 "Python/bytecodes.c" + #line 2199 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 1887 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2200 "Python/bytecodes.c" + #line 2202 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 1894 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2205 "Python/bytecodes.c" + #line 2207 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 1898 "Python/executor_cases.c.h" stack_pointer[-1] = b; @@ -1902,7 +1902,7 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2309 "Python/bytecodes.c" + #line 2311 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -1919,7 +1919,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2317 "Python/bytecodes.c" + #line 2319 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -1928,7 +1928,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2322 "Python/bytecodes.c" + #line 2324 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1945,7 +1945,7 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2334 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 1952 "Python/executor_cases.c.h" @@ -1957,7 +1957,7 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2337 "Python/bytecodes.c" + #line 2339 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 1964 "Python/executor_cases.c.h" @@ -1970,7 +1970,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2342 "Python/bytecodes.c" + #line 2344 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -1983,12 +1983,12 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2348 "Python/bytecodes.c" + #line 2350 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 1990 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2351 "Python/bytecodes.c" + #line 2353 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 1994 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -1998,7 +1998,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2355 "Python/bytecodes.c" + #line 2357 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2023,7 +2023,7 @@ } #line 2025 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2378 "Python/bytecodes.c" + #line 2380 "Python/bytecodes.c" } #line 2029 "Python/executor_cases.c.h" stack_pointer[-1] = iter; @@ -2035,7 +2035,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2610 "Python/bytecodes.c" + #line 2612 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2065,7 +2065,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2649 "Python/bytecodes.c" + #line 2651 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2084,7 +2084,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3019 "Python/bytecodes.c" + #line 3050 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2100,7 +2100,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3433 "Python/bytecodes.c" + #line 3464 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2120,7 +2120,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3447 "Python/bytecodes.c" + #line 3478 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2156,13 +2156,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3497 "Python/bytecodes.c" + #line 3528 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 2162 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3499 "Python/bytecodes.c" + #line 3530 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 2168 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -2174,7 +2174,7 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3503 "Python/bytecodes.c" + #line 3534 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -2189,7 +2189,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3512 "Python/bytecodes.c" + #line 3543 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2209,7 +2209,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3525 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -2223,7 +2223,7 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3532 "Python/bytecodes.c" + #line 3563 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 2230 "Python/executor_cases.c.h" @@ -2266,7 +2266,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3557 "Python/bytecodes.c" + #line 3588 "Python/bytecodes.c" assert(oparg >= 2); #line 2272 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index eb8b50e5c905d4..11823cf9cd293c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2563,7 +2563,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1815 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2599,7 +2599,7 @@ */ #line 2601 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1849 "Python/bytecodes.c" + #line 1851 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2610,7 +2610,7 @@ res = PyObject_GetAttr(owner, name); #line 2612 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1858 "Python/bytecodes.c" + #line 1860 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2617 "Python/generated_cases.c.h" @@ -2627,7 +2627,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1867 "Python/bytecodes.c" + #line 1869 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2655,7 +2655,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1883 "Python/bytecodes.c" + #line 1885 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2683,7 +2683,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1899 "Python/bytecodes.c" + #line 1901 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2725,7 +2725,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1929 "Python/bytecodes.c" + #line 1931 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2750,7 +2750,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1942 "Python/bytecodes.c" + #line 1944 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2776,7 +2776,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1957 "Python/bytecodes.c" + #line 1959 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2808,7 +2808,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1983 "Python/bytecodes.c" + #line 1985 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2842,7 +2842,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2011 "Python/bytecodes.c" + #line 2013 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2871,7 +2871,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 2031 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2921,7 +2921,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2072 "Python/bytecodes.c" + #line 2074 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2943,7 +2943,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2091 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2959,7 +2959,7 @@ #line 2960 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2104 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2978,7 +2978,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2114 "Python/bytecodes.c" + #line 2116 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -3001,7 +3001,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2129 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -3028,7 +3028,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2148 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -3052,12 +3052,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2163 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 3058 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2165 "Python/bytecodes.c" + #line 2167 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3063 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3069,12 +3069,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2169 "Python/bytecodes.c" + #line 2171 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 3075 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2171 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; #line 3081 "Python/generated_cases.c.h" @@ -3088,12 +3088,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2176 "Python/bytecodes.c" + #line 2178 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 3094 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2178 "Python/bytecodes.c" + #line 2180 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3104,7 +3104,7 @@ #line 3105 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2186 "Python/bytecodes.c" + #line 2188 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3123,19 +3123,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2197 "Python/bytecodes.c" + #line 2199 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 3130 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2200 "Python/bytecodes.c" + #line 2202 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 3137 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2205 "Python/bytecodes.c" + #line 2207 "Python/bytecodes.c" b = res ? Py_True : Py_False; #line 3141 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -3146,13 +3146,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2209 "Python/bytecodes.c" + #line 2211 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 3153 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2212 "Python/bytecodes.c" + #line 2214 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 3158 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3163,7 +3163,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2216 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -3174,14 +3174,14 @@ } TARGET(JUMP_FORWARD) { - #line 2222 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" JUMPBY(oparg); #line 3180 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2226 "Python/bytecodes.c" + #line 2228 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); @@ -3205,7 +3205,7 @@ } TARGET(ENTER_EXECUTOR) { - #line 2257 "Python/bytecodes.c" + #line 2259 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); PyCodeObject *code = _PyFrame_GetCode(frame); @@ -3225,7 +3225,7 @@ TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2274 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); #line 3232 "Python/generated_cases.c.h" @@ -3235,7 +3235,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2279 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); #line 3242 "Python/generated_cases.c.h" @@ -3245,11 +3245,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2284 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 3251 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2286 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" JUMPBY(oparg); } #line 3256 "Python/generated_cases.c.h" @@ -3259,14 +3259,14 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2291 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { #line 3268 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2296 "Python/bytecodes.c" + #line 2298 "Python/bytecodes.c" } #line 3272 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -3274,7 +3274,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2300 "Python/bytecodes.c" + #line 2302 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -3288,7 +3288,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2309 "Python/bytecodes.c" + #line 2311 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -3305,7 +3305,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2317 "Python/bytecodes.c" + #line 2319 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -3314,7 +3314,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2322 "Python/bytecodes.c" + #line 2324 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3331,7 +3331,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2334 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; #line 3338 "Python/generated_cases.c.h" @@ -3343,7 +3343,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2337 "Python/bytecodes.c" + #line 2339 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; #line 3350 "Python/generated_cases.c.h" @@ -3356,7 +3356,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2342 "Python/bytecodes.c" + #line 2344 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -3369,12 +3369,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2348 "Python/bytecodes.c" + #line 2350 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 3376 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2351 "Python/bytecodes.c" + #line 2353 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 3380 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3384,7 +3384,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2355 "Python/bytecodes.c" + #line 2357 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3409,7 +3409,7 @@ } #line 3411 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2378 "Python/bytecodes.c" + #line 2380 "Python/bytecodes.c" } #line 3415 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -3421,7 +3421,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2396 "Python/bytecodes.c" + #line 2398 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3461,7 +3461,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2430 "Python/bytecodes.c" + #line 2432 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3494,7 +3494,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2458 "Python/bytecodes.c" + #line 2460 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3525,7 +3525,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2481 "Python/bytecodes.c" + #line 2483 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3556,7 +3556,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2504 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3584,7 +3584,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2525 "Python/bytecodes.c" + #line 2527 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3607,7 +3607,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2543 "Python/bytecodes.c" + #line 2545 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3632,7 +3632,7 @@ } #line 3634 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2566 "Python/bytecodes.c" + #line 2568 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3650,7 +3650,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2575 "Python/bytecodes.c" + #line 2577 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3678,7 +3678,7 @@ } #line 3680 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2601 "Python/bytecodes.c" + #line 2603 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3697,7 +3697,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2610 "Python/bytecodes.c" + #line 2612 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3727,7 +3727,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2649 "Python/bytecodes.c" + #line 2651 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3751,7 +3751,8 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2661 "Python/bytecodes.c" + #line 2663 "Python/bytecodes.c" + assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3767,11 +3768,10 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - assert(oparg & 1); #line 3772 "Python/generated_cases.c.h" - STACK_GROW(((oparg & 1) ? 1 : 0)); + STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } @@ -3782,7 +3782,8 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2680 "Python/bytecodes.c" + #line 2682 "Python/bytecodes.c" + assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3791,11 +3792,68 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - assert(oparg & 1); #line 3796 "Python/generated_cases.c.h" - STACK_GROW(((oparg & 1) ? 1 : 0)); + STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } + next_instr += 9; + DISPATCH(); + } + + TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { + PyObject *self = stack_pointer[-1]; + PyObject *res2 = NULL; + PyObject *res; + uint32_t type_version = read_u32(&next_instr[1].cache); + uint32_t keys_version = read_u32(&next_instr[3].cache); + PyObject *descr = read_obj(&next_instr[5].cache); + #line 2694 "Python/bytecodes.c" + assert((oparg & 1) == 0); + PyTypeObject *self_cls = Py_TYPE(self); + assert(type_version != 0); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; + DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + keys_version, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + #line 3824 "Python/generated_cases.c.h" + Py_DECREF(self); + #line 2707 "Python/bytecodes.c" + res = Py_NewRef(descr); + #line 3828 "Python/generated_cases.c.h" + STACK_GROW((0 ? 1 : 0)); + stack_pointer[-1] = res; + if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } + next_instr += 9; + DISPATCH(); + } + + TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { + PyObject *self = stack_pointer[-1]; + PyObject *res2 = NULL; + PyObject *res; + uint32_t type_version = read_u32(&next_instr[1].cache); + PyObject *descr = read_obj(&next_instr[5].cache); + #line 2711 "Python/bytecodes.c" + assert((oparg & 1) == 0); + PyTypeObject *self_cls = Py_TYPE(self); + assert(type_version != 0); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + #line 3850 "Python/generated_cases.c.h" + Py_DECREF(self); + #line 2719 "Python/bytecodes.c" + res = Py_NewRef(descr); + #line 3854 "Python/generated_cases.c.h" + STACK_GROW((0 ? 1 : 0)); + stack_pointer[-1] = res; + if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } @@ -3806,7 +3864,8 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2692 "Python/bytecodes.c" + #line 2723 "Python/bytecodes.c" + assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3819,26 +3878,25 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - assert(oparg & 1); - #line 3824 "Python/generated_cases.c.h" - STACK_GROW(((oparg & 1) ? 1 : 0)); + #line 3882 "Python/generated_cases.c.h" + STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(KW_NAMES) { - #line 2708 "Python/bytecodes.c" + #line 2739 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3837 "Python/generated_cases.c.h" + #line 3895 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2714 "Python/bytecodes.c" + #line 2745 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3851,7 +3909,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3855 "Python/generated_cases.c.h" + #line 3913 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3861,7 +3919,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2760 "Python/bytecodes.c" + #line 2791 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3943,7 +4001,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3947 "Python/generated_cases.c.h" + #line 4005 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3955,7 +4013,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2848 "Python/bytecodes.c" + #line 2879 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3965,7 +4023,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3969 "Python/generated_cases.c.h" + #line 4027 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3974,7 +4032,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2860 "Python/bytecodes.c" + #line 2891 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4000,7 +4058,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4004 "Python/generated_cases.c.h" + #line 4062 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4008,7 +4066,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2888 "Python/bytecodes.c" + #line 2919 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4044,7 +4102,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4048 "Python/generated_cases.c.h" + #line 4106 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4052,7 +4110,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2926 "Python/bytecodes.c" + #line 2957 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4062,7 +4120,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4066 "Python/generated_cases.c.h" + #line 4124 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4075,7 +4133,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2938 "Python/bytecodes.c" + #line 2969 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4086,7 +4144,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4090 "Python/generated_cases.c.h" + #line 4148 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4100,7 +4158,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2952 "Python/bytecodes.c" + #line 2983 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4111,7 +4169,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4115 "Python/generated_cases.c.h" + #line 4173 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4124,7 +4182,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2966 "Python/bytecodes.c" + #line 2997 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4175,12 +4233,12 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4179 "Python/generated_cases.c.h" + #line 4237 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3019 "Python/bytecodes.c" + #line 3050 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4188,7 +4246,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4192 "Python/generated_cases.c.h" + #line 4250 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4198,7 +4256,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3029 "Python/bytecodes.c" + #line 3060 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4220,7 +4278,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4224 "Python/generated_cases.c.h" + #line 4282 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4234,7 +4292,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3054 "Python/bytecodes.c" + #line 3085 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4262,7 +4320,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4266 "Python/generated_cases.c.h" + #line 4324 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4276,7 +4334,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3085 "Python/bytecodes.c" + #line 3116 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4308,7 +4366,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4312 "Python/generated_cases.c.h" + #line 4370 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4322,7 +4380,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3120 "Python/bytecodes.c" + #line 3151 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4354,7 +4412,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4358 "Python/generated_cases.c.h" + #line 4416 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4368,7 +4426,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3155 "Python/bytecodes.c" + #line 3186 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4393,7 +4451,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4397 "Python/generated_cases.c.h" + #line 4455 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4406,7 +4464,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3182 "Python/bytecodes.c" + #line 3213 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4433,7 +4491,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4437 "Python/generated_cases.c.h" + #line 4495 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4445,7 +4503,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3212 "Python/bytecodes.c" + #line 3243 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4463,14 +4521,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4467 "Python/generated_cases.c.h" + #line 4525 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3232 "Python/bytecodes.c" + #line 3263 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4501,7 +4559,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4505 "Python/generated_cases.c.h" + #line 4563 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4514,7 +4572,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3266 "Python/bytecodes.c" + #line 3297 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4543,7 +4601,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4547 "Python/generated_cases.c.h" + #line 4605 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4556,7 +4614,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3298 "Python/bytecodes.c" + #line 3329 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4585,7 +4643,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4589 "Python/generated_cases.c.h" + #line 4647 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4598,7 +4656,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3330 "Python/bytecodes.c" + #line 3361 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4626,7 +4684,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4630 "Python/generated_cases.c.h" + #line 4688 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4636,9 +4694,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3361 "Python/bytecodes.c" + #line 3392 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4642 "Python/generated_cases.c.h" + #line 4700 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4647,7 +4705,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3365 "Python/bytecodes.c" + #line 3396 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4709,14 +4767,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4713 "Python/generated_cases.c.h" + #line 4771 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3427 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4720 "Python/generated_cases.c.h" + #line 4778 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4727,7 +4785,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3433 "Python/bytecodes.c" + #line 3464 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4739,7 +4797,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4743 "Python/generated_cases.c.h" + #line 4801 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4747,7 +4805,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3447 "Python/bytecodes.c" + #line 3478 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4772,14 +4830,14 @@ default: Py_UNREACHABLE(); } - #line 4776 "Python/generated_cases.c.h" + #line 4834 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3474 "Python/bytecodes.c" + #line 3505 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4800,7 +4858,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4804 "Python/generated_cases.c.h" + #line 4862 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4808,15 +4866,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3497 "Python/bytecodes.c" + #line 3528 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4814 "Python/generated_cases.c.h" + #line 4872 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3499 "Python/bytecodes.c" + #line 3530 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4820 "Python/generated_cases.c.h" + #line 4878 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4826,14 +4884,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3503 "Python/bytecodes.c" + #line 3534 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4837 "Python/generated_cases.c.h" + #line 4895 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4841,7 +4899,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3512 "Python/bytecodes.c" + #line 3543 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4852,7 +4910,7 @@ else { res = value; } - #line 4856 "Python/generated_cases.c.h" + #line 4914 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4861,12 +4919,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3525 "Python/bytecodes.c" + #line 3556 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4870 "Python/generated_cases.c.h" + #line 4928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4875,10 +4933,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3532 "Python/bytecodes.c" + #line 3563 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4882 "Python/generated_cases.c.h" + #line 4940 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4890,7 +4948,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3537 "Python/bytecodes.c" + #line 3568 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4905,12 +4963,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4909 "Python/generated_cases.c.h" + #line 4967 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3552 "Python/bytecodes.c" + #line 3583 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4914 "Python/generated_cases.c.h" + #line 4972 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4920,16 +4978,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3557 "Python/bytecodes.c" + #line 3588 "Python/bytecodes.c" assert(oparg >= 2); - #line 4926 "Python/generated_cases.c.h" + #line 4984 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3561 "Python/bytecodes.c" + #line 3592 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4941,48 +4999,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4945 "Python/generated_cases.c.h" + #line 5003 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3575 "Python/bytecodes.c" + #line 3606 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4951 "Python/generated_cases.c.h" + #line 5009 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3579 "Python/bytecodes.c" + #line 3610 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4959 "Python/generated_cases.c.h" + #line 5017 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3584 "Python/bytecodes.c" + #line 3615 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4970 "Python/generated_cases.c.h" + #line 5028 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3592 "Python/bytecodes.c" + #line 3623 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4981 "Python/generated_cases.c.h" + #line 5039 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3600 "Python/bytecodes.c" + #line 3631 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4994,12 +5052,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4998 "Python/generated_cases.c.h" + #line 5056 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3614 "Python/bytecodes.c" + #line 3645 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5011,30 +5069,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5015 "Python/generated_cases.c.h" + #line 5073 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3628 "Python/bytecodes.c" + #line 3659 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5026 "Python/generated_cases.c.h" + #line 5084 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3636 "Python/bytecodes.c" + #line 3667 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5033 "Python/generated_cases.c.h" + #line 5091 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3641 "Python/bytecodes.c" + #line 3672 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5040 "Python/generated_cases.c.h" + #line 5098 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 70e1ca44ce7663..92768e60f62ab0 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -378,6 +378,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case LOAD_ATTR_METHOD_NO_DICT: return 1; + case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: + return 1; + case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: + return 1; case LOAD_ATTR_METHOD_LAZY_DICT: return 1; case KW_NAMES: @@ -815,11 +819,15 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case PUSH_EXC_INFO: return 2; case LOAD_ATTR_METHOD_WITH_VALUES: - return ((oparg & 1) ? 1 : 0) + 1; + return (1 ? 1 : 0) + 1; case LOAD_ATTR_METHOD_NO_DICT: - return ((oparg & 1) ? 1 : 0) + 1; + return (1 ? 1 : 0) + 1; + case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: + return (0 ? 1 : 0) + 1; + case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: + return (0 ? 1 : 0) + 1; case LOAD_ATTR_METHOD_LAZY_DICT: - return ((oparg & 1) ? 1 : 0) + 1; + return (1 ? 1 : 0) + 1; case KW_NAMES: return 0; case INSTRUMENTED_CALL: @@ -1120,6 +1128,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 }, [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG }, [KW_NAMES] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 1a1ad97e00135a..d84d253c912a28 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -80,14 +80,14 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_COMPARE_OP_FLOAT, - &&TARGET_COMPARE_OP_INT, + &&TARGET_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, + &&TARGET_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, &&TARGET_RETURN_VALUE, - &&TARGET_COMPARE_OP_STR, + &&TARGET_COMPARE_OP_FLOAT, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_FOR_ITER_LIST, + &&TARGET_COMPARE_OP_INT, &&TARGET_LOAD_LOCALS, - &&TARGET_FOR_ITER_TUPLE, + &&TARGET_COMPARE_OP_STR, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, + &&TARGET_FOR_ITER_LIST, + &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, - &&TARGET_FOR_ITER_GEN, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -131,11 +131,11 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, &&TARGET_GET_AWAITABLE, - &&TARGET_CALL_PY_EXACT_ARGS, + &&TARGET_FOR_ITER_GEN, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_MAKE_CELL, - &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, @@ -147,26 +147,26 @@ static void *opcode_targets[256] = { &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, - &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_COPY_FREE_VARS, &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_CALL_NO_KW_STR_1, - &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, &&TARGET_CONVERT_VALUE, + &&TARGET_CALL_NO_KW_TUPLE_1, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_CALL_NO_KW_BUILTIN_O, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_CALL_NO_KW_LEN, - &&TARGET_CALL_NO_KW_ISINSTANCE, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_LOAD_FAST_LOAD_FAST, &&TARGET_STORE_FAST_LOAD_FAST, &&TARGET_STORE_FAST_STORE_FAST, @@ -177,6 +177,8 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, &&TARGET_LOAD_FROM_DICT_OR_DEREF, &&TARGET_SET_FUNCTION_ATTRIBUTE, + &&TARGET_CALL_NO_KW_LEN, + &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LIST_APPEND, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, @@ -227,8 +229,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_ENTER_EXECUTOR, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index a3fce2e6775912..dcf4be712db20d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -711,8 +711,8 @@ specialize_dict_access( return 1; } -static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, - PyObject* descr, DescriptorClassification kind); +static int specialize_attr_loadclassattr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, + PyObject* descr, DescriptorClassification kind, bool is_method); static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); void @@ -753,7 +753,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { int oparg = instr->op.arg; if (oparg & 1) { - if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) { + if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, true)) { goto success; } } @@ -872,10 +872,14 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPEC_FAIL_ATTR_NOT_MANAGED_DICT); goto fail; case NON_DESCRIPTOR: - SPECIALIZATION_FAIL(LOAD_ATTR, - (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ? - SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE : - SPEC_FAIL_ATTR_NOT_MANAGED_DICT); + if ((instr->op.arg & 1) == 0) { + if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, false)) { + goto success; + } + } + else { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); + } goto fail; case ABSENT: if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR, @@ -1064,13 +1068,14 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, // can cause a significant drop in cache hits. A possible test is // python.exe -m test_typing test_re test_dis test_zlib. static int -specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, -PyObject *descr, DescriptorClassification kind) +specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, +PyObject *descr, DescriptorClassification kind, bool is_method) { _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); PyTypeObject *owner_cls = Py_TYPE(owner); - assert(kind == METHOD && descr != NULL); + assert(descr != NULL); + assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR)); if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; @@ -1090,7 +1095,7 @@ PyObject *descr, DescriptorClassification kind) return 0; } write_u32(cache->keys_version, keys_version); - instr->op.code = LOAD_ATTR_METHOD_WITH_VALUES; + instr->op.code = is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; } else { Py_ssize_t dictoffset = owner_cls->tp_dictoffset; @@ -1099,9 +1104,9 @@ PyObject *descr, DescriptorClassification kind) return 0; } if (dictoffset == 0) { - instr->op.code = LOAD_ATTR_METHOD_NO_DICT; + instr->op.code = is_method ? LOAD_ATTR_METHOD_NO_DICT : LOAD_ATTR_NONDESCRIPTOR_NO_DICT; } - else { + else if (is_method) { PyObject *dict = *(PyObject **) ((char *)owner + dictoffset); if (dict) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); @@ -1111,6 +1116,10 @@ PyObject *descr, DescriptorClassification kind) assert(owner_cls->tp_dictoffset <= INT16_MAX); instr->op.code = LOAD_ATTR_METHOD_LAZY_DICT; } + else { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); + return 0; + } } /* `descr` is borrowed. This is safe for methods (even inherited ones from * super classes!) as long as tp_version_tag is validated for two main reasons: From 51ea664d18938645521bdd128a3c55f9c197644c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 10 Jul 2023 14:04:34 +0300 Subject: [PATCH 327/446] gh-99593: Add tests for Unicode C API (part 3) (GH-104728) Add tests for codecs. --- Lib/test/test_capi/test_codecs.py | 466 +++++++++++++++++++++++++++ Modules/_testcapi/unicode.c | 507 +++++++++++++++++++++++++++++- 2 files changed, 972 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_capi/test_codecs.py b/Lib/test/test_capi/test_codecs.py index e46726192aa05b..682c56979c6dfa 100644 --- a/Lib/test/test_capi/test_codecs.py +++ b/Lib/test/test_capi/test_codecs.py @@ -1,10 +1,95 @@ import unittest +import sys from test.support import import_helper _testcapi = import_helper.import_module('_testcapi') +NULL = None + class CAPITest(unittest.TestCase): + # TODO: Test the following functions: + # + # PyUnicode_BuildEncodingMap + # PyUnicode_FSConverter + # PyUnicode_FSDecoder + # PyUnicode_DecodeMBCS + # PyUnicode_DecodeMBCSStateful + # PyUnicode_DecodeCodePageStateful + # PyUnicode_AsMBCSString + # PyUnicode_EncodeCodePage + # PyUnicode_DecodeLocaleAndSize + # PyUnicode_DecodeLocale + # PyUnicode_EncodeLocale + # PyUnicode_DecodeFSDefault + # PyUnicode_DecodeFSDefaultAndSize + # PyUnicode_EncodeFSDefault + + def test_fromencodedobject(self): + """Test PyUnicode_FromEncodedObject()""" + fromencodedobject = _testcapi.unicode_fromencodedobject + + self.assertEqual(fromencodedobject(b'abc', NULL), 'abc') + self.assertEqual(fromencodedobject(b'abc', 'ascii'), 'abc') + b = b'a\xc2\xa1\xe4\xbd\xa0\xf0\x9f\x98\x80' + s = 'a\xa1\u4f60\U0001f600' + self.assertEqual(fromencodedobject(b, NULL), s) + self.assertEqual(fromencodedobject(b, 'utf-8'), s) + self.assertEqual(fromencodedobject(b, 'latin1'), b.decode('latin1')) + self.assertRaises(UnicodeDecodeError, fromencodedobject, b, 'ascii') + self.assertEqual(fromencodedobject(b, 'ascii', 'replace'), + 'a' + '\ufffd'*9) + self.assertEqual(fromencodedobject(bytearray(b), NULL), s) + self.assertEqual(fromencodedobject(bytearray(b), 'utf-8'), s) + self.assertRaises(LookupError, fromencodedobject, b'abc', 'foo') + self.assertRaises(LookupError, fromencodedobject, b, 'ascii', 'foo') + self.assertRaises(TypeError, fromencodedobject, 'abc', NULL) + self.assertRaises(TypeError, fromencodedobject, 'abc', 'ascii') + self.assertRaises(TypeError, fromencodedobject, [], NULL) + self.assertRaises(TypeError, fromencodedobject, [], 'ascii') + self.assertRaises(SystemError, fromencodedobject, NULL, NULL) + self.assertRaises(SystemError, fromencodedobject, NULL, 'ascii') + + def test_decode(self): + """Test PyUnicode_Decode()""" + decode = _testcapi.unicode_decode + + self.assertEqual(decode(b'[\xe2\x82\xac]', 'utf-8'), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', 'iso8859-15'), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', 'iso8859-15', 'strict'), '[\u20ac]') + self.assertRaises(UnicodeDecodeError, decode, b'[\xa4]', 'utf-8') + self.assertEqual(decode(b'[\xa4]', 'utf-8', 'replace'), '[\ufffd]') + + self.assertEqual(decode(b'[\xe2\x82\xac]', NULL), '[\u20ac]') + self.assertEqual(decode(b'[\xa4]', NULL, 'replace'), '[\ufffd]') + + self.assertRaises(LookupError, decode, b'\xa4', 'foo') + self.assertRaises(LookupError, decode, b'\xa4', 'utf-8', 'foo') + # TODO: Test PyUnicode_Decode() with NULL as data and + # negative size. + + def test_asencodedstring(self): + """Test PyUnicode_AsEncodedString()""" + asencodedstring = _testcapi.unicode_asencodedstring + + self.assertEqual(asencodedstring('abc', NULL), b'abc') + self.assertEqual(asencodedstring('abc', 'ascii'), b'abc') + s = 'a\xa1\u4f60\U0001f600' + b = b'a\xc2\xa1\xe4\xbd\xa0\xf0\x9f\x98\x80' + self.assertEqual(asencodedstring(s, NULL), b) + self.assertEqual(asencodedstring(s, 'utf-8'), b) + self.assertEqual(asencodedstring('\xa1\xa2', 'latin1'), b'\xa1\xa2') + self.assertRaises(UnicodeEncodeError, asencodedstring, '\xa1\xa2', 'ascii') + self.assertEqual(asencodedstring(s, 'ascii', 'replace'), b'a???') + + self.assertRaises(LookupError, asencodedstring, 'abc', 'foo') + self.assertRaises(LookupError, asencodedstring, s, 'ascii', 'foo') + self.assertRaises(TypeError, asencodedstring, b'abc', NULL) + self.assertRaises(TypeError, asencodedstring, b'abc', 'ascii') + self.assertRaises(TypeError, asencodedstring, [], NULL) + self.assertRaises(TypeError, asencodedstring, [], 'ascii') + # CRASHES asencodedstring(NULL, NULL) + # CRASHES asencodedstring(NULL, 'ascii') def test_decodeutf8(self): """Test PyUnicode_DecodeUTF8()""" @@ -49,6 +134,387 @@ def test_decodeutf8stateful(self): # TODO: Test PyUnicode_DecodeUTF8Stateful() with NULL as the address of # "consumed". + def test_asutf8string(self): + """Test PyUnicode_AsUTF8String()""" + asutf8string = _testcapi.unicode_asutf8string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf8string(s), s.encode('utf-8')) + + self.assertRaises(UnicodeEncodeError, asutf8string, '\ud8ff') + self.assertRaises(TypeError, asutf8string, b'abc') + self.assertRaises(TypeError, asutf8string, []) + # CRASHES asutf8string(NULL) + + def test_decodeutf16(self): + """Test PyUnicode_DecodeUTF16()""" + decodeutf16 = _testcapi.unicode_decodeutf16 + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-16') + self.assertEqual(decodeutf16(0, b), (naturalbyteorder, s)) + b = s.encode('utf-16le') + self.assertEqual(decodeutf16(-1, b), (-1, s)) + self.assertEqual(decodeutf16(0, b'\xff\xfe'+b), (-1, s)) + b = s.encode('utf-16be') + self.assertEqual(decodeutf16(1, b), (1, s)) + self.assertEqual(decodeutf16(0, b'\xfe\xff'+b), (1, s)) + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'a') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'a') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xff\xfea') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xfe\xffa') + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'\x00\xde') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'\xde\x00') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xde\xde') + self.assertEqual(decodeutf16(-1, b'\x00\xde', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(1, b'\xde\x00', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xde\xde', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xff\xfe\x00\xde', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xfe\xff\xde\x00', 'replace'), (1, '\ufffd')) + + self.assertRaises(UnicodeDecodeError, decodeutf16, -1, b'\x3d\xd8') + self.assertRaises(UnicodeDecodeError, decodeutf16, 1, b'\xd8\x3d') + self.assertRaises(UnicodeDecodeError, decodeutf16, 0, b'\xd8\xd8') + self.assertEqual(decodeutf16(-1, b'\x3d\xd8', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(1, b'\xd8\x3d', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xd8\xd8', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xff\xfe\x3d\xd8', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf16(0, b'\xfe\xff\xd8\x3d', 'replace'), (1, '\ufffd')) + + self.assertRaises(LookupError, decodeutf16, -1, b'\x00\xde', 'foo') + self.assertRaises(LookupError, decodeutf16, 1, b'\xde\x00', 'foo') + self.assertRaises(LookupError, decodeutf16, 0, b'\xde\xde', 'foo') + # TODO: Test PyUnicode_DecodeUTF16() with NULL as data and + # negative size. + + def test_decodeutf16stateful(self): + """Test PyUnicode_DecodeUTF16Stateful()""" + decodeutf16stateful = _testcapi.unicode_decodeutf16stateful + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-16') + self.assertEqual(decodeutf16stateful(0, b), (naturalbyteorder, s, len(b))) + b = s.encode('utf-16le') + self.assertEqual(decodeutf16stateful(-1, b), (-1, s, len(b))) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe'+b), (-1, s, len(b)+2)) + b = s.encode('utf-16be') + self.assertEqual(decodeutf16stateful(1, b), (1, s, len(b))) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff'+b), (1, s, len(b)+2)) + + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d\xd8'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(-1, b'\x61\x00\x3d\xd8\x00'), (-1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8\x3d'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(1, b'\x00\x61\xd8\x3d\xde'), (1, 'a', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe\x61\x00\x3d\xd8\x00'), (-1, 'a', 4)) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff\x00\x61\xd8\x3d\xde'), (1, 'a', 4)) + + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, -1, b'\x00\xde') + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 1, b'\xde\x00') + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 0, b'\xde\xde') + self.assertEqual(decodeutf16stateful(-1, b'\x00\xde', 'replace'), (-1, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(1, b'\xde\x00', 'replace'), (1, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xde\xde', 'replace'), (0, '\ufffd', 2)) + self.assertEqual(decodeutf16stateful(0, b'\xff\xfe\x00\xde', 'replace'), (-1, '\ufffd', 4)) + self.assertEqual(decodeutf16stateful(0, b'\xfe\xff\xde\x00', 'replace'), (1, '\ufffd', 4)) + + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, -1, b'\x3d\xd8\x61\x00') + self.assertEqual(decodeutf16stateful(-1, b'\x3d\xd8\x61\x00', 'replace'), (-1, '\ufffda', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf16stateful, 1, b'\xd8\x3d\x00\x61') + self.assertEqual(decodeutf16stateful(1, b'\xd8\x3d\x00\x61', 'replace'), (1, '\ufffda', 4)) + + self.assertRaises(LookupError, decodeutf16stateful, -1, b'\x00\xde', 'foo') + self.assertRaises(LookupError, decodeutf16stateful, 1, b'\xde\x00', 'foo') + self.assertRaises(LookupError, decodeutf16stateful, 0, b'\xde\xde', 'foo') + # TODO: Test PyUnicode_DecodeUTF16Stateful() with NULL as data and + # negative size. + # TODO: Test PyUnicode_DecodeUTF16Stateful() with NULL as the address of + # "consumed". + + def test_asutf16string(self): + """Test PyUnicode_AsUTF16String()""" + asutf16string = _testcapi.unicode_asutf16string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf16string(s), s.encode('utf-16')) + + self.assertRaises(UnicodeEncodeError, asutf16string, '\ud8ff') + self.assertRaises(TypeError, asutf16string, b'abc') + self.assertRaises(TypeError, asutf16string, []) + # CRASHES asutf16string(NULL) + + def test_decodeutf32(self): + """Test PyUnicode_DecodeUTF8()""" + decodeutf32 = _testcapi.unicode_decodeutf32 + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-32') + self.assertEqual(decodeutf32(0, b), (naturalbyteorder, s)) + b = s.encode('utf-32le') + self.assertEqual(decodeutf32(-1, b), (-1, s)) + self.assertEqual(decodeutf32(0, b'\xff\xfe\x00\x00'+b), (-1, s)) + b = s.encode('utf-32be') + self.assertEqual(decodeutf32(1, b), (1, s)) + self.assertEqual(decodeutf32(0, b'\x00\x00\xfe\xff'+b), (1, s)) + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\x61\x00\x00\x00\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\x00\x00\x00\x61\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\xff\xfe\x00\x00\x61\x00\x00\x00\x00') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\x00\x00\xfe\xff\x00\x00\x00\x61\x00') + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32, 0, b'\xff\xff\xff\xff') + self.assertEqual(decodeutf32(-1, b'\xff\xff\xff\xff', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf32(1, b'\xff\xff\xff\xff', 'replace'), (1, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\xff\xff\xff\xff', 'replace'), (0, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\xff\xfe\x00\x00\xff\xff\xff\xff', 'replace'), (-1, '\ufffd')) + self.assertEqual(decodeutf32(0, b'\x00\x00\xfe\xff\xff\xff\xff\xff', 'replace'), (1, '\ufffd')) + + self.assertRaises(UnicodeDecodeError, decodeutf32, -1, b'\x3d\xd8\x00\x00') + self.assertEqual(decodeutf32(-1, b'\x3d\xd8\x00\x00', 'replace'), (-1, '\ufffd')) + self.assertRaises(UnicodeDecodeError, decodeutf32, 1, b'\x00\x00\xd8\x3d') + self.assertEqual(decodeutf32(1, b'\x00\x00\xd8\x3d', 'replace'), (1, '\ufffd')) + + self.assertRaises(LookupError, decodeutf32, -1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32, 1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32, 0, b'\xff\xff\xff\xff', 'foo') + # TODO: Test PyUnicode_DecodeUTF32() with NULL as data and + # negative size. + + def test_decodeutf32stateful(self): + """Test PyUnicode_DecodeUTF32Stateful()""" + decodeutf32stateful = _testcapi.unicode_decodeutf32stateful + + naturalbyteorder = -1 if sys.byteorder == 'little' else 1 + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + b = s.encode('utf-32') + self.assertEqual(decodeutf32stateful(0, b), (naturalbyteorder, s, len(b))) + b = s.encode('utf-32le') + self.assertEqual(decodeutf32stateful(-1, b), (-1, s, len(b))) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00'+b), (-1, s, len(b)+4)) + b = s.encode('utf-32be') + self.assertEqual(decodeutf32stateful(1, b), (1, s, len(b))) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff'+b), (1, s, len(b)+4)) + + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00\xf6'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(-1, b'\x61\x00\x00\x00\x00\xf6\x01'), (-1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00\x01'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\x00\x61\x00\x01\xf6'), (1, 'a', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00\x61\x00\x00\x00\x00\xf6\x01'), (-1, 'a', 8)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff\x00\x00\x00\x61\x00\x01\xf6'), (1, 'a', 8)) + + for b in b'\xff', b'\xff\xff', b'\xff\xff\xff': + self.assertEqual(decodeutf32stateful(-1, b), (-1, '', 0)) + self.assertEqual(decodeutf32stateful(1, b), (1, '', 0)) + self.assertEqual(decodeutf32stateful(0, b), (0, '', 0)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00'+b), (-1, '', 4)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff'+b), (1, '', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, -1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 1, b'\xff\xff\xff\xff') + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 0, b'\xff\xff\xff\xff') + self.assertEqual(decodeutf32stateful(-1, b'\xff\xff\xff\xff', 'replace'), (-1, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(1, b'\xff\xff\xff\xff', 'replace'), (1, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xff\xff\xff', 'replace'), (0, '\ufffd', 4)) + self.assertEqual(decodeutf32stateful(0, b'\xff\xfe\x00\x00\xff\xff\xff\xff', 'replace'), (-1, '\ufffd', 8)) + self.assertEqual(decodeutf32stateful(0, b'\x00\x00\xfe\xff\xff\xff\xff\xff', 'replace'), (1, '\ufffd', 8)) + + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, -1, b'\x3d\xd8\x00\x00') + self.assertEqual(decodeutf32stateful(-1, b'\x3d\xd8\x00\x00', 'replace'), (-1, '\ufffd', 4)) + self.assertRaises(UnicodeDecodeError, decodeutf32stateful, 1, b'\x00\x00\xd8\x3d') + self.assertEqual(decodeutf32stateful(1, b'\x00\x00\xd8\x3d', 'replace'), (1, '\ufffd', 4)) + + self.assertRaises(LookupError, decodeutf32stateful, -1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32stateful, 1, b'\xff\xff\xff\xff', 'foo') + self.assertRaises(LookupError, decodeutf32stateful, 0, b'\xff\xff\xff\xff', 'foo') + # TODO: Test PyUnicode_DecodeUTF32Stateful() with NULL as data and + # negative size. + # TODO: Test PyUnicode_DecodeUTF32Stateful() with NULL as the address of + # "consumed". + + def test_asutf32string(self): + """Test PyUnicode_AsUTF32String()""" + asutf32string = _testcapi.unicode_asutf32string + + for s in ['abc', '\xa1\xa2', '\u4f60\u597d', 'a\U0001f600']: + self.assertEqual(asutf32string(s), s.encode('utf-32')) + + self.assertRaises(UnicodeEncodeError, asutf32string, '\ud8ff') + self.assertRaises(TypeError, asutf32string, b'abc') + self.assertRaises(TypeError, asutf32string, []) + # CRASHES asutf32string(NULL) + + def test_decodelatin1(self): + """Test PyUnicode_DecodeLatin1()""" + decodelatin1 = _testcapi.unicode_decodelatin1 + + self.assertEqual(decodelatin1(b'abc'), 'abc') + self.assertEqual(decodelatin1(b'abc', 'strict'), 'abc') + self.assertEqual(decodelatin1(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodelatin1(b'\xa1\xa2', 'strict'), '\xa1\xa2') + # TODO: Test PyUnicode_DecodeLatin1() with NULL as data and + # negative size. + + def test_aslatin1string(self): + """Test PyUnicode_AsLatin1String()""" + aslatin1string = _testcapi.unicode_aslatin1string + + self.assertEqual(aslatin1string('abc'), b'abc') + self.assertEqual(aslatin1string('\xa1\xa2'), b'\xa1\xa2') + + self.assertRaises(UnicodeEncodeError, aslatin1string, '\u4f60') + self.assertRaises(TypeError, aslatin1string, b'abc') + self.assertRaises(TypeError, aslatin1string, []) + # CRASHES aslatin1string(NULL) + + def test_decodeascii(self): + """Test PyUnicode_DecodeASCII()""" + decodeascii = _testcapi.unicode_decodeascii + + self.assertEqual(decodeascii(b'abc'), 'abc') + self.assertEqual(decodeascii(b'abc', 'strict'), 'abc') + + self.assertRaises(UnicodeDecodeError, decodeascii, b'\xff') + self.assertEqual(decodeascii(b'a\xff', 'replace'), 'a\ufffd') + self.assertEqual(decodeascii(b'a\xffb', 'replace'), 'a\ufffdb') + + self.assertRaises(LookupError, decodeascii, b'a\xff', 'foo') + # TODO: Test PyUnicode_DecodeASCII() with NULL as data and + # negative size. + + def test_asasciistring(self): + """Test PyUnicode_AsASCIIString()""" + asasciistring = _testcapi.unicode_asasciistring + + self.assertEqual(asasciistring('abc'), b'abc') + + self.assertRaises(UnicodeEncodeError, asasciistring, '\x80') + self.assertRaises(TypeError, asasciistring, b'abc') + self.assertRaises(TypeError, asasciistring, []) + # CRASHES asasciistring(NULL) + + def test_decodecharmap(self): + """Test PyUnicode_DecodeCharmap()""" + decodecharmap = _testcapi.unicode_decodecharmap + + self.assertEqual(decodecharmap(b'\3\0\7', {0: 'a', 3: 'b', 7: 'c'}), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['a', 'b', 'c']), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', 'abc'), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['\xa1', '\xa2', '\xa3']), '\xa2\xa1\xa3') + self.assertEqual(decodecharmap(b'\1\0\2', ['\u4f60', '\u597d', '\u4e16']), '\u597d\u4f60\u4e16') + self.assertEqual(decodecharmap(b'\1\0\2', ['\U0001f600', '\U0001f601', '\U0001f602']), '\U0001f601\U0001f600\U0001f602') + + self.assertEqual(decodecharmap(b'\1\0\2', [97, 98, 99]), 'bac') + self.assertEqual(decodecharmap(b'\1\0\2', ['', 'b', 'cd']), 'bcd') + + self.assertRaises(UnicodeDecodeError, decodecharmap, b'\0', {}) + self.assertRaises(UnicodeDecodeError, decodecharmap, b'\0', {0: None}) + self.assertEqual(decodecharmap(b'\1\0\2', [None, 'b', 'c'], 'replace'), 'b\ufffdc') + self.assertEqual(decodecharmap(b'\1\0\2\xff', NULL), '\1\0\2\xff') + self.assertRaises(TypeError, decodecharmap, b'\0', 42) + + # TODO: Test PyUnicode_DecodeCharmap() with NULL as data and + # negative size. + + def test_ascharmapstring(self): + """Test PyUnicode_AsCharmapString()""" + ascharmapstring = _testcapi.unicode_ascharmapstring + + self.assertEqual(ascharmapstring('abc', {97: 3, 98: 0, 99: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\xa1\xa2\xa3', {0xa1: 3, 0xa2: 0, 0xa3: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\u4f60\u597d\u4e16', {0x4f60: 3, 0x597d: 0, 0x4e16: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('\U0001f600\U0001f601\U0001f602', {0x1f600: 3, 0x1f601: 0, 0x1f602: 7}), b'\3\0\7') + self.assertEqual(ascharmapstring('abc', {97: 3, 98: b'', 99: b'spam'}), b'\3spam') + + self.assertRaises(UnicodeEncodeError, ascharmapstring, 'a', {}) + self.assertRaises(UnicodeEncodeError, ascharmapstring, 'a', {97: None}) + self.assertRaises(TypeError, ascharmapstring, b'a', {}) + self.assertRaises(TypeError, ascharmapstring, [], {}) + self.assertRaises(TypeError, ascharmapstring, 'a', NULL) + # CRASHES ascharmapstring(NULL, {}) + + def test_decodeunicodeescape(self): + """Test PyUnicode_DecodeUnicodeEscape()""" + decodeunicodeescape = _testcapi.unicode_decodeunicodeescape + + self.assertEqual(decodeunicodeescape(b'abc'), 'abc') + self.assertEqual(decodeunicodeescape(br'\t\n\r\x0b\x0c\x00\\'), '\t\n\r\v\f\0\\') + self.assertEqual(decodeunicodeescape(b'\t\n\r\x0b\x0c\x00'), '\t\n\r\v\f\0') + self.assertEqual(decodeunicodeescape(br'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodeunicodeescape(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decodeunicodeescape(br'\u4f60\u597d'), '\u4f60\u597d') + self.assertEqual(decodeunicodeescape(br'\U0001f600'), '\U0001f600') + with self.assertWarns(DeprecationWarning): + self.assertEqual(decodeunicodeescape(br'\z'), r'\z') + + for b in b'\\', br'\xa', br'\u4f6', br'\U0001f60': + self.assertRaises(UnicodeDecodeError, decodeunicodeescape, b) + self.assertRaises(UnicodeDecodeError, decodeunicodeescape, b, 'strict') + self.assertEqual(decodeunicodeescape(br'x\U0001f60', 'replace'), 'x\ufffd') + self.assertEqual(decodeunicodeescape(br'x\U0001f60y', 'replace'), 'x\ufffdy') + + self.assertRaises(LookupError, decodeunicodeescape, b'\\', 'foo') + # TODO: Test PyUnicode_DecodeUnicodeEscape() with NULL as data and + # negative size. + + def test_asunicodeescapestring(self): + """Test PyUnicode_AsUnicodeEscapeString()""" + asunicodeescapestring = _testcapi.unicode_asunicodeescapestring + + self.assertEqual(asunicodeescapestring('abc'), b'abc') + self.assertEqual(asunicodeescapestring('\t\n\r\v\f\0\\'), br'\t\n\r\x0b\x0c\x00\\') + self.assertEqual(asunicodeescapestring('\xa1\xa2'), br'\xa1\xa2') + self.assertEqual(asunicodeescapestring('\u4f60\u597d'), br'\u4f60\u597d') + self.assertEqual(asunicodeescapestring('\U0001f600'), br'\U0001f600') + + self.assertRaises(TypeError, asunicodeescapestring, b'abc') + self.assertRaises(TypeError, asunicodeescapestring, []) + # CRASHES asunicodeescapestring(NULL) + + def test_decoderawunicodeescape(self): + """Test PyUnicode_DecodeRawUnicodeEscape()""" + decoderawunicodeescape = _testcapi.unicode_decoderawunicodeescape + + self.assertEqual(decoderawunicodeescape(b'abc'), 'abc') + self.assertEqual(decoderawunicodeescape(b'\t\n\r\v\f\0\\'), '\t\n\r\v\f\0\\') + self.assertEqual(decoderawunicodeescape(b'\xa1\xa2'), '\xa1\xa2') + self.assertEqual(decoderawunicodeescape(br'\u4f60\u597d'), '\u4f60\u597d') + self.assertEqual(decoderawunicodeescape(br'\U0001f600'), '\U0001f600') + self.assertEqual(decoderawunicodeescape(br'\xa1\xa2'), r'\xa1\xa2') + self.assertEqual(decoderawunicodeescape(br'\z'), r'\z') + + for b in br'\u4f6', br'\U0001f60': + self.assertRaises(UnicodeDecodeError, decoderawunicodeescape, b) + self.assertRaises(UnicodeDecodeError, decoderawunicodeescape, b, 'strict') + self.assertEqual(decoderawunicodeescape(br'x\U0001f60', 'replace'), 'x\ufffd') + self.assertEqual(decoderawunicodeescape(br'x\U0001f60y', 'replace'), 'x\ufffdy') + + self.assertRaises(LookupError, decoderawunicodeescape, br'\U0001f60', 'foo') + # TODO: Test PyUnicode_DecodeRawUnicodeEscape() with NULL as data and + # negative size. + + def test_asrawunicodeescapestring(self): + """Test PyUnicode_AsRawUnicodeEscapeString()""" + asrawunicodeescapestring = _testcapi.unicode_asrawunicodeescapestring + + self.assertEqual(asrawunicodeescapestring('abc'), b'abc') + self.assertEqual(asrawunicodeescapestring('\t\n\r\v\f\0\\'), b'\t\n\r\v\f\0\\') + self.assertEqual(asrawunicodeescapestring('\xa1\xa2'), b'\xa1\xa2') + self.assertEqual(asrawunicodeescapestring('\u4f60\u597d'), br'\u4f60\u597d') + self.assertEqual(asrawunicodeescapestring('\U0001f600'), br'\U0001f600') + + self.assertRaises(TypeError, asrawunicodeescapestring, b'abc') + self.assertRaises(TypeError, asrawunicodeescapestring, []) + # CRASHES asrawunicodeescapestring(NULL) + if __name__ == "__main__": unittest.main() diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c index 51d741a6b5ff1c..b4c6c4b5e3ce1a 100644 --- a/Modules/_testcapi/unicode.c +++ b/Modules/_testcapi/unicode.c @@ -375,6 +375,22 @@ unicode_readchar(PyObject *self, PyObject *args) return PyLong_FromUnsignedLong(result); } +/* Test PyUnicode_FromEncodedObject() */ +static PyObject * +unicode_fromencodedobject(PyObject *self, PyObject *args) +{ + PyObject *obj; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "Oz|z", &obj, &encoding, &errors)) { + return NULL; + } + + NULLABLE(obj); + return PyUnicode_FromEncodedObject(obj, encoding, errors); +} + /* Test PyUnicode_FromObject() */ static PyObject * unicode_fromobject(PyObject *self, PyObject *arg) @@ -660,6 +676,78 @@ unicode_getdefaultencoding(PyObject *self, PyObject *Py_UNUSED(ignored)) return PyBytes_FromString(s); } +/* Test PyUnicode_Decode() */ +static PyObject * +unicode_decode(PyObject *self, PyObject *args) +{ + const char *s; + Py_ssize_t size; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#z|z", &s, &size, &encoding, &errors)) + return NULL; + + return PyUnicode_Decode(s, size, encoding, errors); +} + +/* Test PyUnicode_AsEncodedString() */ +static PyObject * +unicode_asencodedstring(PyObject *self, PyObject *args) +{ + PyObject *unicode; + const char *encoding; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "Oz|z", &unicode, &encoding, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_AsEncodedString(unicode, encoding, errors); +} + +/* Test PyUnicode_BuildEncodingMap() */ +static PyObject * +unicode_buildencodingmap(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_BuildEncodingMap(arg); +} + +/* Test PyUnicode_DecodeUTF7() */ +static PyObject * +unicode_decodeutf7(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeUTF7(data, size, errors); +} + +/* Test PyUnicode_DecodeUTF7Stateful() */ +static PyObject * +unicode_decodeutf7stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF7Stateful(data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + /* Test PyUnicode_DecodeUTF8() */ static PyObject * unicode_decodeutf8(PyObject *self, PyObject *args) @@ -694,6 +782,387 @@ unicode_decodeutf8stateful(PyObject *self, PyObject *args) return Py_BuildValue("(Nn)", result, consumed); } +/* Test PyUnicode_AsUTF8String() */ +static PyObject * +unicode_asutf8string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF8String(arg); +} + +/* Test PyUnicode_DecodeUTF32() */ +static PyObject * +unicode_decodeutf32(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF32(data, size, errors, &byteorder); + if (!result) { + return NULL; + } + return Py_BuildValue("(iN)", byteorder, result); +} + +/* Test PyUnicode_DecodeUTF32Stateful() */ +static PyObject * +unicode_decodeutf32stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF32Stateful(data, size, errors, &byteorder, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(iNn)", byteorder, result, consumed); +} + +/* Test PyUnicode_AsUTF32String() */ +static PyObject * +unicode_asutf32string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF32String(arg); +} + +/* Test PyUnicode_DecodeUTF16() */ +static PyObject * +unicode_decodeutf16(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = 0; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF16(data, size, errors, &byteorder); + if (!result) { + return NULL; + } + return Py_BuildValue("(iN)", byteorder, result); +} + +/* Test PyUnicode_DecodeUTF16Stateful() */ +static PyObject * +unicode_decodeutf16stateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &byteorder, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeUTF16Stateful(data, size, errors, &byteorder, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(iNn)", byteorder, result, consumed); +} + +/* Test PyUnicode_AsUTF16String() */ +static PyObject * +unicode_asutf16string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUTF16String(arg); +} + +/* Test PyUnicode_DecodeUnicodeEscape() */ +static PyObject * +unicode_decodeunicodeescape(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeUnicodeEscape(data, size, errors); +} + +/* Test PyUnicode_AsUnicodeEscapeString() */ +static PyObject * +unicode_asunicodeescapestring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsUnicodeEscapeString(arg); +} + +static PyObject * +unicode_decoderawunicodeescape(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeRawUnicodeEscape(data, size, errors); +} + +/* Test PyUnicode_AsRawUnicodeEscapeString() */ +static PyObject * +unicode_asrawunicodeescapestring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsRawUnicodeEscapeString(arg); +} + +static PyObject * +unicode_decodelatin1(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLatin1(data, size, errors); +} + +/* Test PyUnicode_AsLatin1String() */ +static PyObject * +unicode_aslatin1string(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsLatin1String(arg); +} + +/* Test PyUnicode_DecodeASCII() */ +static PyObject * +unicode_decodeascii(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeASCII(data, size, errors); +} + +/* Test PyUnicode_AsASCIIString() */ +static PyObject * +unicode_asasciistring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsASCIIString(arg); +} + +/* Test PyUnicode_DecodeCharmap() */ +static PyObject * +unicode_decodecharmap(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + PyObject *mapping; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#O|z", &data, &size, &mapping, &errors)) + return NULL; + + NULLABLE(mapping); + return PyUnicode_DecodeCharmap(data, size, mapping, errors); +} + +/* Test PyUnicode_AsCharmapString() */ +static PyObject * +unicode_ascharmapstring(PyObject *self, PyObject *args) +{ + PyObject *unicode; + PyObject *mapping; + + if (!PyArg_ParseTuple(args, "OO", &unicode, &mapping)) + return NULL; + + NULLABLE(unicode); + NULLABLE(mapping); + return PyUnicode_AsCharmapString(unicode, mapping); +} + +#ifdef MS_WINDOWS + +/* Test PyUnicode_DecodeMBCS() */ +static PyObject * +unicode_decodembcs(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeMBCS(data, size, errors); +} + +/* Test PyUnicode_DecodeMBCSStateful() */ +static PyObject * +unicode_decodembcsstateful(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeMBCSStateful(data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + +/* Test PyUnicode_DecodeCodePageStateful() */ +static PyObject * +unicode_decodecodepagestateful(PyObject *self, PyObject *args) +{ + int code_page; + const char *data; + Py_ssize_t size; + const char *errors = NULL; + Py_ssize_t consumed; + PyObject *result; + + if (!PyArg_ParseTuple(args, "iy#|z", &code_page, &data, &size, &errors)) + return NULL; + + result = PyUnicode_DecodeCodePageStateful(code_page, data, size, errors, &consumed); + if (!result) { + return NULL; + } + return Py_BuildValue("(Nn)", result, consumed); +} + +/* Test PyUnicode_AsMBCSString() */ +static PyObject * +unicode_asmbcsstring(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_AsMBCSString(arg); +} + +/* Test PyUnicode_EncodeCodePage() */ +static PyObject * +unicode_encodecodepage(PyObject *self, PyObject *args) +{ + int code_page; + PyObject *unicode; + const char *errors; + + if (!PyArg_ParseTuple(args, "iO|z", &code_page, &unicode, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_EncodeCodePage(code_page, unicode, errors); +} + +#endif /* MS_WINDOWS */ + +/* Test PyUnicode_DecodeLocaleAndSize() */ +static PyObject * +unicode_decodelocaleandsize(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLocaleAndSize(data, size, errors); +} + +/* Test PyUnicode_DecodeLocale() */ +static PyObject * +unicode_decodelocale(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors; + + if (!PyArg_ParseTuple(args, "y#|z", &data, &size, &errors)) + return NULL; + + return PyUnicode_DecodeLocale(data, errors); +} + +/* Test PyUnicode_EncodeLocale() */ +static PyObject * +unicode_encodelocale(PyObject *self, PyObject *args) +{ + PyObject *unicode; + const char *errors; + + if (!PyArg_ParseTuple(args, "O|z", &unicode, &errors)) + return NULL; + + NULLABLE(unicode); + return PyUnicode_EncodeLocale(unicode, errors); +} + +/* Test PyUnicode_DecodeFSDefault() */ +static PyObject * +unicode_decodefsdefault(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "y#", &data, &size)) + return NULL; + + return PyUnicode_DecodeFSDefault(data); +} + +/* Test PyUnicode_DecodeFSDefaultAndSize() */ +static PyObject * +unicode_decodefsdefaultandsize(PyObject *self, PyObject *args) +{ + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "y#|n", &data, &size, &size)) + return NULL; + + return PyUnicode_DecodeFSDefaultAndSize(data, size); +} + +/* Test PyUnicode_EncodeFSDefault() */ +static PyObject * +unicode_encodefsdefault(PyObject *self, PyObject *arg) +{ + NULLABLE(arg); + return PyUnicode_EncodeFSDefault(arg); +} + /* Test PyUnicode_Concat() */ static PyObject * unicode_concat(PyObject *self, PyObject *args) @@ -1519,6 +1988,7 @@ static PyMethodDef TestMethods[] = { {"unicode_substring", unicode_substring, METH_VARARGS}, {"unicode_getlength", unicode_getlength, METH_O}, {"unicode_readchar", unicode_readchar, METH_VARARGS}, + {"unicode_fromencodedobject",unicode_fromencodedobject, METH_VARARGS}, {"unicode_fromobject", unicode_fromobject, METH_O}, {"unicode_interninplace", unicode_interninplace, METH_O}, {"unicode_internfromstring", unicode_internfromstring, METH_O}, @@ -1533,9 +2003,44 @@ static PyMethodDef TestMethods[] = { {"unicode_asutf8", unicode_asutf8, METH_VARARGS}, {"unicode_asutf8andsize", unicode_asutf8andsize, METH_VARARGS}, {"unicode_asutf8andsize_null",unicode_asutf8andsize_null, METH_VARARGS}, + {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, + {"unicode_decode", unicode_decode, METH_VARARGS}, + {"unicode_asencodedstring", unicode_asencodedstring, METH_VARARGS}, + {"unicode_buildencodingmap", unicode_buildencodingmap, METH_O}, + {"unicode_decodeutf7", unicode_decodeutf7, METH_VARARGS}, + {"unicode_decodeutf7stateful",unicode_decodeutf7stateful, METH_VARARGS}, {"unicode_decodeutf8", unicode_decodeutf8, METH_VARARGS}, {"unicode_decodeutf8stateful",unicode_decodeutf8stateful, METH_VARARGS}, - {"unicode_getdefaultencoding",unicode_getdefaultencoding, METH_NOARGS}, + {"unicode_asutf8string", unicode_asutf8string, METH_O}, + {"unicode_decodeutf16", unicode_decodeutf16, METH_VARARGS}, + {"unicode_decodeutf16stateful",unicode_decodeutf16stateful, METH_VARARGS}, + {"unicode_asutf16string", unicode_asutf16string, METH_O}, + {"unicode_decodeutf32", unicode_decodeutf32, METH_VARARGS}, + {"unicode_decodeutf32stateful",unicode_decodeutf32stateful, METH_VARARGS}, + {"unicode_asutf32string", unicode_asutf32string, METH_O}, + {"unicode_decodeunicodeescape",unicode_decodeunicodeescape, METH_VARARGS}, + {"unicode_asunicodeescapestring",unicode_asunicodeescapestring,METH_O}, + {"unicode_decoderawunicodeescape",unicode_decoderawunicodeescape,METH_VARARGS}, + {"unicode_asrawunicodeescapestring",unicode_asrawunicodeescapestring,METH_O}, + {"unicode_decodelatin1", unicode_decodelatin1, METH_VARARGS}, + {"unicode_aslatin1string", unicode_aslatin1string, METH_O}, + {"unicode_decodeascii", unicode_decodeascii, METH_VARARGS}, + {"unicode_asasciistring", unicode_asasciistring, METH_O}, + {"unicode_decodecharmap", unicode_decodecharmap, METH_VARARGS}, + {"unicode_ascharmapstring", unicode_ascharmapstring, METH_VARARGS}, +#ifdef MS_WINDOWS + {"unicode_decodembcs", unicode_decodembcs, METH_VARARGS}, + {"unicode_decodembcsstateful",unicode_decodembcsstateful, METH_VARARGS}, + {"unicode_decodecodepagestateful",unicode_decodecodepagestateful,METH_VARARGS}, + {"unicode_asmbcsstring", unicode_asmbcsstring, METH_O}, + {"unicode_encodecodepage", unicode_encodecodepage, METH_VARARGS}, +#endif /* MS_WINDOWS */ + {"unicode_decodelocaleandsize",unicode_decodelocaleandsize, METH_VARARGS}, + {"unicode_decodelocale", unicode_decodelocale, METH_VARARGS}, + {"unicode_encodelocale", unicode_encodelocale, METH_VARARGS}, + {"unicode_decodefsdefault", unicode_decodefsdefault, METH_VARARGS}, + {"unicode_decodefsdefaultandsize",unicode_decodefsdefaultandsize,METH_VARARGS}, + {"unicode_encodefsdefault", unicode_encodefsdefault, METH_O}, {"unicode_concat", unicode_concat, METH_VARARGS}, {"unicode_splitlines", unicode_splitlines, METH_VARARGS}, {"unicode_split", unicode_split, METH_VARARGS}, From 8fb6edf479b2cf58d503945d17467055a5eaf455 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Mon, 10 Jul 2023 17:18:03 +0530 Subject: [PATCH 328/446] GH-104787: use managed weakrefs in `_asyncio` (#106516) --- Modules/_asynciomodule.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 3843f9c45d7236..3b0550279fb49c 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -120,7 +120,6 @@ typedef enum { PyObject *prefix##_result; \ PyObject *prefix##_source_tb; \ PyObject *prefix##_cancel_msg; \ - PyObject *prefix##_weakreflist; \ PyObject *prefix##_cancelled_exc; \ fut_state prefix##_state; \ /* These bitfields need to be at the end of the struct @@ -1502,11 +1501,6 @@ static PyMethodDef FutureType_methods[] = { {NULL, NULL} /* Sentinel */ }; -static PyMemberDef FutureType_members[] = { - {"__weaklistoffset__", T_PYSSIZET, offsetof(FutureObj, fut_weakreflist), READONLY}, - {NULL}, -}; - #define FUTURE_COMMON_GETSETLIST \ {"_state", (getter)FutureObj_get_state, NULL, NULL}, \ {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, \ @@ -1537,7 +1531,6 @@ static PyType_Slot Future_slots[] = { {Py_tp_clear, (inquiry)FutureObj_clear}, {Py_tp_iter, (getiterfunc)future_new_iter}, {Py_tp_methods, FutureType_methods}, - {Py_tp_members, FutureType_members}, {Py_tp_getset, FutureType_getsetlist}, {Py_tp_init, (initproc)_asyncio_Future___init__}, {Py_tp_new, PyType_GenericNew}, @@ -1552,7 +1545,8 @@ static PyType_Spec Future_spec = { .name = "_asyncio.Future", .basicsize = sizeof(FutureObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT | + Py_TPFLAGS_MANAGED_WEAKREF), .slots = Future_slots, }; @@ -1569,9 +1563,7 @@ FutureObj_dealloc(PyObject *self) PyTypeObject *tp = Py_TYPE(fut); PyObject_GC_UnTrack(self); - if (fut->fut_weakreflist != NULL) { - PyObject_ClearWeakRefs(self); - } + PyObject_ClearWeakRefs(self); (void)FutureObj_clear(fut); tp->tp_free(fut); @@ -2642,11 +2634,6 @@ static PyMethodDef TaskType_methods[] = { {NULL, NULL} /* Sentinel */ }; -static PyMemberDef TaskType_members[] = { - {"__weaklistoffset__", T_PYSSIZET, offsetof(TaskObj, task_weakreflist), READONLY}, - {NULL}, -}; - static PyGetSetDef TaskType_getsetlist[] = { FUTURE_COMMON_GETSETLIST {"_log_destroy_pending", (getter)TaskObj_get_log_destroy_pending, @@ -2665,7 +2652,6 @@ static PyType_Slot Task_slots[] = { {Py_tp_clear, (inquiry)TaskObj_clear}, {Py_tp_iter, (getiterfunc)future_new_iter}, {Py_tp_methods, TaskType_methods}, - {Py_tp_members, TaskType_members}, {Py_tp_getset, TaskType_getsetlist}, {Py_tp_init, (initproc)_asyncio_Task___init__}, {Py_tp_new, PyType_GenericNew}, @@ -2680,7 +2666,8 @@ static PyType_Spec Task_spec = { .name = "_asyncio.Task", .basicsize = sizeof(TaskObj), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT), + Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT | + Py_TPFLAGS_MANAGED_WEAKREF), .slots = Task_slots, }; @@ -2697,9 +2684,7 @@ TaskObj_dealloc(PyObject *self) PyTypeObject *tp = Py_TYPE(task); PyObject_GC_UnTrack(self); - if (task->task_weakreflist != NULL) { - PyObject_ClearWeakRefs(self); - } + PyObject_ClearWeakRefs(self); (void)TaskObj_clear(task); tp->tp_free(task); From abe4ca5ecf3abb6ad72ba18ed732a0bc3f158335 Mon Sep 17 00:00:00 2001 From: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Date: Mon, 10 Jul 2023 19:51:14 +0800 Subject: [PATCH 329/446] update release schedule for 3.13 (#106577) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4a4c8ab65dceff..4ab26565a13e03 100644 --- a/README.rst +++ b/README.rst @@ -238,7 +238,7 @@ All current PEPs, as well as guidelines for submitting a new PEP, are listed at Release Schedule ---------------- -See :pep:`XXX` for Python 3.13 release details. +See :pep:`719` for Python 3.13 release details. Copyright and License Information From 43389e4a3a15daaa2c4ea7059637e2fce3f38966 Mon Sep 17 00:00:00 2001 From: Riahiamirreza <54557628+Riahiamirreza@users.noreply.github.com> Date: Mon, 10 Jul 2023 15:22:41 +0330 Subject: [PATCH 330/446] Fix typo in datamodel.rst (#106587) --- Doc/reference/datamodel.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 7f5edbbcadca6c..8a10a34347c2de 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1625,7 +1625,7 @@ access (use of, assignment to, or deletion of ``x.name``) for class instances. :meth:`__getattr__` and :meth:`__setattr__`.) This is done both for efficiency reasons and because otherwise :meth:`__getattr__` would have no way to access other attributes of the instance. Note that at least for instance variables, - you can fake total control by not inserting any values in the instance attribute + you can take total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the :meth:`__getattribute__` method below for a way to actually get total control over attribute access. From 93846657a35726358ef6714c6631a9f862090b04 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Mon, 10 Jul 2023 19:57:25 +0800 Subject: [PATCH 331/446] gh-106078: Move static variables initialized once to decimal module global state (#106475) --- Modules/_decimal/_decimal.c | 50 ++++++++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 3 -- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 7e1809cfb98b29..89924b205f99e9 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,12 @@ #include "docstrings.h" +#ifdef EXTRA_FUNCTIONALITY + #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD +#else + #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) +#endif + struct PyDecContextObject; typedef struct { @@ -68,6 +74,13 @@ typedef struct { /* Basic and extended context templates */ PyObject *basic_context_template; PyObject *extended_context_template; + + PyObject *round_map[_PY_DEC_ROUND_GUARD]; + + /* Convert rationals for comparison */ + PyObject *Rational; + + PyObject *SignalTuple; } decimal_state; static decimal_state global_state; @@ -216,13 +229,6 @@ static const char *dec_signal_string[MPD_NUM_FLAGS] = { "Underflow", }; -#ifdef EXTRA_FUNCTIONALITY - #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD -#else - #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) -#endif -static PyObject *round_map[_PY_DEC_ROUND_GUARD]; - static const char *invalid_rounding_err = "valid values for rounding are:\n\ [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\ @@ -520,15 +526,16 @@ static int getround(PyObject *v) { int i; + decimal_state *state = GLOBAL_STATE(); if (PyUnicode_Check(v)) { for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (v == round_map[i]) { + if (v == state->round_map[i]) { return i; } } for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (PyUnicode_Compare(v, round_map[i]) == 0) { + if (PyUnicode_Compare(v, state->round_map[i]) == 0) { return i; } } @@ -561,11 +568,11 @@ signaldict_len(PyObject *self UNUSED) return SIGNAL_MAP_LEN; } -static PyObject *SignalTuple; static PyObject * signaldict_iter(PyObject *self UNUSED) { - return PyTuple_Type.tp_iter(SignalTuple); + decimal_state *state = GLOBAL_STATE(); + return PyTuple_Type.tp_iter(state->SignalTuple); } static PyObject * @@ -754,8 +761,9 @@ static PyObject * context_getround(PyObject *self, void *closure UNUSED) { int i = mpd_getround(CTX(self)); + decimal_state *state = GLOBAL_STATE(); - return Py_NewRef(round_map[i]); + return Py_NewRef(state->round_map[i]); } static PyObject * @@ -2987,8 +2995,6 @@ convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) /* Implicit conversions to Decimal for comparison */ /******************************************************************************/ -/* Convert rationals for comparison */ -static PyObject *Rational = NULL; static PyObject * multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) { @@ -3117,7 +3123,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } } else { - int is_rational = PyObject_IsInstance(w, Rational); + int is_rational = PyObject_IsInstance(w, state->Rational); if (is_rational < 0) { *wcmp = NULL; } @@ -5865,7 +5871,7 @@ PyInit__decimal(void) (PyObject *)state->PyDec_Type)); Py_CLEAR(obj); /* Rational is a global variable used for fraction comparisons. */ - ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); + ASSIGN_PTR(state->Rational, PyObject_GetAttrString(numbers, "Rational")); /* Done with numbers, Number */ Py_CLEAR(numbers); Py_CLEAR(Number); @@ -5912,7 +5918,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddType(m, (PyTypeObject *)state->DecimalException)); /* Create signal tuple */ - ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); + ASSIGN_PTR(state->SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) { @@ -5953,7 +5959,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); /* add to signal tuple */ - PyTuple_SET_ITEM(SignalTuple, i, Py_NewRef(cm->ex)); + PyTuple_SET_ITEM(state->SignalTuple, i, Py_NewRef(cm->ex)); } /* @@ -6029,8 +6035,8 @@ PyInit__decimal(void) /* Init string constants */ for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - ASSIGN_PTR(round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); - CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(round_map[i]))); + ASSIGN_PTR(state->round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); + CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(state->round_map[i]))); } /* Add specification version number */ @@ -6045,11 +6051,11 @@ PyInit__decimal(void) Py_CLEAR(obj); /* GCOV_NOT_REACHED */ Py_CLEAR(numbers); /* GCOV_NOT_REACHED */ Py_CLEAR(Number); /* GCOV_NOT_REACHED */ - Py_CLEAR(Rational); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ - Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 12f91726b2d2f7..38b47d06e4a5f9 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -422,9 +422,6 @@ Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - global_state - -Modules/_decimal/_decimal.c - round_map - -Modules/_decimal/_decimal.c - Rational - -Modules/_decimal/_decimal.c - SignalTuple - ## state Modules/_asynciomodule.c - fi_freelist - From 3f9bc86c5a1b29fd636a53bf4150acacf60284d8 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Mon, 10 Jul 2023 18:01:26 +0530 Subject: [PATCH 332/446] GH-100288: regen cases after #105990 (#106589) --- Python/executor_cases.c.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 0ef752249ccb76..eccb30348173af 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1642,7 +1642,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1815 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1678,7 +1678,7 @@ */ #line 1680 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1849 "Python/bytecodes.c" + #line 1851 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1689,7 +1689,7 @@ res = PyObject_GetAttr(owner, name); #line 1691 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1858 "Python/bytecodes.c" + #line 1860 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 1696 "Python/executor_cases.c.h" @@ -1704,7 +1704,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2091 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1720,7 +1720,7 @@ #line 1721 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2104 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2237,7 +2237,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3537 "Python/bytecodes.c" + #line 3568 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2255,7 +2255,7 @@ #line 2256 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3552 "Python/bytecodes.c" + #line 3583 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2261 "Python/executor_cases.c.h" STACK_SHRINK(1); From 3e23fa71f43fb225ca29a931644d1100e2f4d6b8 Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Mon, 10 Jul 2023 15:35:54 +0200 Subject: [PATCH 333/446] GH-61215: threadingmock: Remove unused branch for `timeout` (#106591) threadingmock: Remove unused branch for `timeout` This is no longer needed as the mock does not hold a "timeout" parameter, the timeout is stored in `_mock_wait_timeout`. --- Lib/unittest/mock.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 7ef7e7180b31c2..3ed54b3ba230ed 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -3012,9 +3012,7 @@ class ThreadingMixin(Base): DEFAULT_TIMEOUT = None def _get_child_mock(self, /, **kw): - if "timeout" in kw: - kw["timeout"] = kw.pop("timeout") - elif isinstance(kw.get("parent"), ThreadingMixin): + if isinstance(kw.get("parent"), ThreadingMixin): kw["timeout"] = kw["parent"]._mock_wait_timeout elif isinstance(kw.get("_new_parent"), ThreadingMixin): kw["timeout"] = kw["_new_parent"]._mock_wait_timeout From a840806d338805fe74a9de01081d30da7605a29f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 10 Jul 2023 10:41:02 -0600 Subject: [PATCH 334/446] gh-105227: Add PyType_GetDict() (GH-105747) This compensates for static builtin types having `tp_dict` set to `NULL`. Co-authored-by: Petr Viktorin --- Doc/c-api/type.rst | 17 +++++++++++++ Doc/c-api/typeobj.rst | 14 ++++++++++- Include/cpython/object.h | 1 + ...-06-13-14-24-55.gh-issue-105227.HDL9aF.rst | 5 ++++ Modules/_testcapimodule.c | 25 +++++++++++++++++++ Objects/typeobject.c | 7 ++++++ 6 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index c99c7ef93a45df..a5f333e2a31e03 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -50,6 +50,23 @@ Type Objects The return type is now ``unsigned long`` rather than ``long``. +.. c:function:: PyObject* PyType_GetDict(PyTypeObject* type) + + Return the type object's internal namespace, which is otherwise only + exposed via a read-only proxy (``cls.__dict__``). This is a + replacement for accessing :c:member:`~PyTypeObject.tp_dict` directly. + The returned dictionary must be treated as read-only. + + This function is meant for specific embedding and language-binding cases, + where direct access to the dict is necessary and indirect access + (e.g. via the proxy or :c:func:`PyObject_GetAttr`) isn't adequate. + + Extension modules should continue to use ``tp_dict``, + directly or indirectly, when setting up their own types. + + .. versionadded:: 3.12 + + .. c:function:: void PyType_Modified(PyTypeObject *type) Invalidate the internal lookup cache for the type and all of its diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 239c191457f516..7249cfe79c32e9 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -1717,7 +1717,19 @@ and :c:type:`PyType_Type` effectively act as defaults.) called; it may also be initialized to a dictionary containing initial attributes for the type. Once :c:func:`PyType_Ready` has initialized the type, extra attributes for the type may be added to this dictionary only if they don't - correspond to overloaded operations (like :meth:`__add__`). + correspond to overloaded operations (like :meth:`__add__`). Once + initialization for the type has finished, this field should be + treated as read-only. + + Some types may not store their dictionary in this slot. + Use :c:func:`PyType_GetDict` to retreive the dictionary for an arbitrary + type. + + .. versionchanged:: 3.12 + + Internals detail: For static builtin types, this is always ``NULL``. + Instead, the dict for such types is stored on ``PyInterpreterState``. + Use :c:func:`PyType_GetDict` to get the dict for an arbitrary type. **Inheritance:** diff --git a/Include/cpython/object.h b/Include/cpython/object.h index d681435c845459..ef9006431bee2f 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -284,6 +284,7 @@ PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject * PyAPI_FUNC(PyObject *) _PyType_GetDocFromInternalDoc(const char *, const char *); PyAPI_FUNC(PyObject *) _PyType_GetTextSignatureFromInternalDoc(const char *, const char *); PyAPI_FUNC(PyObject *) PyType_GetModuleByDef(PyTypeObject *, PyModuleDef *); +PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *); PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(void) _Py_BreakPoint(void); diff --git a/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst b/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst new file mode 100644 index 00000000000000..846663621e8689 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-13-14-24-55.gh-issue-105227.HDL9aF.rst @@ -0,0 +1,5 @@ +The new :c:func:`PyType_GetDict` provides the dictionary for the given type +object that is normally exposed by ``cls.__dict__``. Normally it's +sufficient to use :c:member:`~PyTypeObject.tp_dict`, but for the static +builtin types :c:member:`!tp_dict` is now always ``NULL``. :c:func:`!PyType_GetDict()` +provides the correct dict object instead. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 50eaff9917fd17..dd2c9c72e53787 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -638,6 +638,30 @@ test_get_type_qualname(PyObject *self, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } +static PyObject * +test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + /* Test for PyType_GetDict */ + + // Assert ints have a `to_bytes` method + PyObject *long_dict = PyType_GetDict(&PyLong_Type); + assert(long_dict); + assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref + Py_DECREF(long_dict); + + // Make a new type, add an attribute to it and assert it's there + PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec); + assert(HeapTypeNameType); + assert(PyObject_SetAttrString( + HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0); + PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType); + assert(type_dict); + assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref + Py_DECREF(HeapTypeNameType); + Py_DECREF(type_dict); + Py_RETURN_NONE; +} + static PyObject * pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) { @@ -3472,6 +3496,7 @@ static PyMethodDef TestMethods[] = { {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS}, {"test_get_type_name", test_get_type_name, METH_NOARGS}, {"test_get_type_qualname", test_get_type_qualname, METH_NOARGS}, + {"test_get_type_dict", test_get_type_dict, METH_NOARGS}, {"_test_thread_state", test_thread_state, METH_VARARGS}, #ifndef MS_WINDOWS {"_spawn_pthread_waiter", spawn_pthread_waiter, METH_NOARGS}, diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 87519efef081c3..5430924e69dee3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -237,6 +237,13 @@ _PyType_GetDict(PyTypeObject *self) return lookup_tp_dict(self); } +PyObject * +PyType_GetDict(PyTypeObject *self) +{ + PyObject *dict = lookup_tp_dict(self); + return _Py_XNewRef(dict); +} + static inline void set_tp_dict(PyTypeObject *self, PyObject *dict) { From 9d582250d8fde240b8e7299b74ba888c574f74a3 Mon Sep 17 00:00:00 2001 From: Ijtaba Hussain Date: Mon, 10 Jul 2023 21:29:03 +0100 Subject: [PATCH 335/446] gh-103186: Fix or catch 'extra' stderr output from unittests (#103196) Reduce test noise by fixing or catching and testing stderr messages from individual tests. test_cmd_line_script.test_script_as_dev_fd calls spawn_python and hence subprocess.Popen with incompatible arguments. On POSIX, pass_fds forces close_fds to be True (subprocess.py line 848). Correct the call. test_uuid.test_cli_namespace_required_for_uuid3: when the namespace is omitted, uuid.main calls argparse.Argument_Parser.error, which prints to stderr before calling sys.exit, which raises SystemExit. Unittest assertRaises catches the exception but not the previous output. Catch the output and test it. test_warnings.test_catchwarnings_with_simplefilter_error similarly prints before raising. Catch the output and test it. --------- Co-authored-by: Oleg Iarygin --- Lib/test/test_cmd_line_script.py | 2 +- Lib/test/test_uuid.py | 9 ++++++--- Lib/test/test_warnings/__init__.py | 10 +++++++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 8bf299382e9ca4..1b588826010717 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -777,7 +777,7 @@ def test_script_as_dev_fd(self): with os_helper.temp_dir() as work_dir: script_name = _make_test_script(work_dir, 'script.py', script) with open(script_name, "r") as fp: - p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=False, pass_fds=(0,1,2,fp.fileno())) + p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=True, pass_fds=(0,1,2,fp.fileno())) out, err = p.communicate() self.assertEqual(out, b"12345678912345678912345\n") diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index a178e942ecda0f..9cec1e87fd3c2d 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -706,20 +706,23 @@ def test_uuid_weakref(self): self.assertIs(strong, weak()) @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-n", "@dns"]) - def test_cli_namespace_required_for_uuid3(self): + @mock.patch('sys.stderr', new_callable=io.StringIO) + def test_cli_namespace_required_for_uuid3(self, mock_err): with self.assertRaises(SystemExit) as cm: self.uuid.main() # Check that exception code is the same as argparse.ArgumentParser.error self.assertEqual(cm.exception.code, 2) + self.assertIn("error: Incorrect number of arguments", mock_err.getvalue()) @mock.patch.object(sys, "argv", ["", "-u", "uuid3", "-N", "python.org"]) - def test_cli_name_required_for_uuid3(self): + @mock.patch('sys.stderr', new_callable=io.StringIO) + def test_cli_name_required_for_uuid3(self, mock_err): with self.assertRaises(SystemExit) as cm: self.uuid.main() - # Check that exception code is the same as argparse.ArgumentParser.error self.assertEqual(cm.exception.code, 2) + self.assertIn("error: Incorrect number of arguments", mock_err.getvalue()) @mock.patch.object(sys, "argv", [""]) def test_cli_uuid4_outputted_with_no_args(self): diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 9e680c847dab7b..83237f5fe0d1b3 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -387,9 +387,13 @@ def test_catchwarnings_with_simplefilter_error(self): with self.module.catch_warnings( module=self.module, action="error", category=FutureWarning ): - self.module.warn("Other types of warnings are not errors") - self.assertRaises(FutureWarning, - self.module.warn, FutureWarning("msg")) + with support.captured_stderr() as stderr: + error_msg = "Other types of warnings are not errors" + self.module.warn(error_msg) + self.assertRaises(FutureWarning, + self.module.warn, FutureWarning("msg")) + stderr = stderr.getvalue() + self.assertIn(error_msg, stderr) class CFilterTests(FilterTests, unittest.TestCase): module = c_warnings From 6782fc050281205734700a1c3e13b123961ed15b Mon Sep 17 00:00:00 2001 From: Louis Paulot <55740424+lpaulot@users.noreply.github.com> Date: Mon, 10 Jul 2023 23:45:27 +0200 Subject: [PATCH 336/446] gh-94777: Fix deadlock in ProcessPoolExecutor (#94784) Fixes a hang in multiprocessing process pool executor when a child process crashes and code could otherwise block on writing to the pipe. See GH-94777 for more details. --- Lib/concurrent/futures/process.py | 4 ++++ Lib/test/test_concurrent_futures.py | 18 ++++++++++++++++++ ...22-07-12-18-45-13.gh-issue-94777.mOybx7.rst | 1 + 3 files changed, 23 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 816edab99f63e3..301207f59de37a 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -499,6 +499,10 @@ def terminate_broken(self, cause): for p in self.processes.values(): p.terminate() + # Prevent queue writing to a pipe which is no longer read. + # https://github.com/python/cpython/issues/94777 + self.call_queue._reader.close() + # clean up resources self.join_executor_internals() diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index a20cb844a293c9..39dbe234e765e8 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -1172,6 +1172,11 @@ def _crash(delay=None): faulthandler._sigsegv() +def _crash_with_data(data): + """Induces a segfault with dummy data in input.""" + _crash() + + def _exit(): """Induces a sys exit with exitcode 1.""" sys.exit(1) @@ -1371,6 +1376,19 @@ def test_shutdown_deadlock_pickle(self): # dangling threads executor_manager.join() + def test_crash_big_data(self): + # Test that there is a clean exception instad of a deadlock when a + # child process crashes while some data is being written into the + # queue. + # https://github.com/python/cpython/issues/94777 + self.executor.shutdown(wait=True) + data = "a" * support.PIPE_MAX_SIZE + with self.executor_type(max_workers=2, + mp_context=self.get_context()) as executor: + self.executor = executor # Allow clean up in fail_on_deadlock + with self.assertRaises(BrokenProcessPool): + list(executor.map(_crash_with_data, [data] * 10)) + create_executor_tests(ExecutorDeadlockTest, executor_mixins=(ProcessPoolForkMixin, diff --git a/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst b/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst new file mode 100644 index 00000000000000..2c04a35fbfce13 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-12-18-45-13.gh-issue-94777.mOybx7.rst @@ -0,0 +1 @@ +Fix hanging :mod:`multiprocessing` ``ProcessPoolExecutor`` when a child process crashes while data is being written in the call queue. From 18dfbd035775c15533d13a98e56b1d2bf5c65f00 Mon Sep 17 00:00:00 2001 From: Thomas Dwyer Date: Mon, 10 Jul 2023 18:00:55 -0500 Subject: [PATCH 337/446] gh-102988: Detect email address parsing errors and return empty tuple to indicate the parsing error (old API) (#105127) Detect email address parsing errors and return empty tuple to indicate the parsing error (old API). This fixes or at least ameliorates CVE-2023-27043. --------- Co-authored-by: Gregory P. Smith --- Doc/library/email.utils.rst | 26 +++++- Doc/whatsnew/3.12.rst | 8 ++ Lib/email/utils.py | 63 +++++++++++++-- Lib/test/test_email/test_email.py | 81 ++++++++++++++++++- ...-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst | 4 + 5 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 345b64001c1ace..a87a0bd2e7de6b 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -65,6 +65,11 @@ of the new API. *email address* parts. Returns a tuple of that information, unless the parse fails, in which case a 2-tuple of ``('', '')`` is returned. + .. versionchanged:: 3.12 + For security reasons, addresses that were ambiguous and could parse into + multiple different addresses now cause ``('', '')`` to be returned + instead of only one of the *potential* addresses. + .. function:: formataddr(pair, charset='utf-8') @@ -87,7 +92,7 @@ of the new API. This method returns a list of 2-tuples of the form returned by ``parseaddr()``. *fieldvalues* is a sequence of header field values as might be returned by :meth:`Message.get_all `. Here's a simple - example that gets all the recipients of a message:: + example that gets all the recipients of a message: from email.utils import getaddresses @@ -97,6 +102,25 @@ of the new API. resent_ccs = msg.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) + When parsing fails for a single fieldvalue, a 2-tuple of ``('', '')`` + is returned in its place. Other errors in parsing the list of + addresses such as a fieldvalue seemingly parsing into multiple + addresses may result in a list containing a single empty 2-tuple + ``[('', '')]`` being returned rather than returning potentially + invalid output. + + Example malformed input parsing: + + .. doctest:: + + >>> from email.utils import getaddresses + >>> getaddresses(['alice@example.com ', 'me@example.com']) + [('', '')] + + .. versionchanged:: 3.12 + The 2-tuple of ``('', '')`` in the returned values when parsing + fails were added as to address a security issue. + .. function:: parsedate(date) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a892f92dd26281..766f468cf9cfbc 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -570,6 +570,14 @@ dis :data:`~dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) +email +----- + +* :func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now return + ``('', '')`` 2-tuples in more situations where invalid email addresses are + encountered instead of potentially inaccurate values. + (Contributed by Thomas Dwyer for :gh:`102988` to ameliorate CVE-2023-27043.) + fractions --------- diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 81da5394ea1695..11ad75e94e9345 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -106,12 +106,54 @@ def formataddr(pair, charset='utf-8'): return address +def _pre_parse_validation(email_header_fields): + accepted_values = [] + for v in email_header_fields: + s = v.replace('\\(', '').replace('\\)', '') + if s.count('(') != s.count(')'): + v = "('', '')" + accepted_values.append(v) + + return accepted_values + + +def _post_parse_validation(parsed_email_header_tuples): + accepted_values = [] + # The parser would have parsed a correctly formatted domain-literal + # The existence of an [ after parsing indicates a parsing failure + for v in parsed_email_header_tuples: + if '[' in v[1]: + v = ('', '') + accepted_values.append(v) + + return accepted_values + def getaddresses(fieldvalues): - """Return a list of (REALNAME, EMAIL) for each fieldvalue.""" - all = COMMASPACE.join(str(v) for v in fieldvalues) + """Return a list of (REALNAME, EMAIL) or ('','') for each fieldvalue. + + When parsing fails for a fieldvalue, a 2-tuple of ('', '') is returned in + its place. + + If the resulting list of parsed address is not the same as the number of + fieldvalues in the input list a parsing error has occurred. A list + containing a single empty 2-tuple [('', '')] is returned in its place. + This is done to avoid invalid output. + """ + fieldvalues = [str(v) for v in fieldvalues] + fieldvalues = _pre_parse_validation(fieldvalues) + all = COMMASPACE.join(v for v in fieldvalues) a = _AddressList(all) - return a.addresslist + result = _post_parse_validation(a.addresslist) + + n = 0 + for v in fieldvalues: + n += v.count(',') + 1 + + if len(result) != n: + return [('', '')] + + return result def _format_timetuple_and_zone(timetuple, zone): @@ -212,9 +254,18 @@ def parseaddr(addr): Return a tuple of realname and email address, unless the parse fails, in which case return a 2-tuple of ('', ''). """ - addrs = _AddressList(addr).addresslist - if not addrs: - return '', '' + if isinstance(addr, list): + addr = addr[0] + + if not isinstance(addr, str): + return ('', '') + + addr = _pre_parse_validation([addr])[0] + addrs = _post_parse_validation(_AddressList(addr).addresslist) + + if not addrs or len(addrs) > 1: + return ('', '') + return addrs[0] diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index 44b405740c4403..5238944d6b4788 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -3319,15 +3319,90 @@ def test_getaddresses(self): [('Al Person', 'aperson@dom.ain'), ('Bud Person', 'bperson@dom.ain')]) + def test_getaddresses_parsing_errors(self): + """Test for parsing errors from CVE-2023-27043""" + eq = self.assertEqual + eq(utils.getaddresses(['alice@example.org(']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org)']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org<']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org>']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org@']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org,']), + [('', 'alice@example.org'), ('', 'bob@example.com')]) + eq(utils.getaddresses(['alice@example.org;']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org:']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org.']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org"']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org[']), + [('', '')]) + eq(utils.getaddresses(['alice@example.org]']), + [('', '')]) + + def test_parseaddr_parsing_errors(self): + """Test for parsing errors from CVE-2023-27043""" + eq = self.assertEqual + eq(utils.parseaddr(['alice@example.org(']), + ('', '')) + eq(utils.parseaddr(['alice@example.org)']), + ('', '')) + eq(utils.parseaddr(['alice@example.org<']), + ('', '')) + eq(utils.parseaddr(['alice@example.org>']), + ('', '')) + eq(utils.parseaddr(['alice@example.org@']), + ('', '')) + eq(utils.parseaddr(['alice@example.org,']), + ('', '')) + eq(utils.parseaddr(['alice@example.org;']), + ('', '')) + eq(utils.parseaddr(['alice@example.org:']), + ('', '')) + eq(utils.parseaddr(['alice@example.org.']), + ('', '')) + eq(utils.parseaddr(['alice@example.org"']), + ('', '')) + eq(utils.parseaddr(['alice@example.org[']), + ('', '')) + eq(utils.parseaddr(['alice@example.org]']), + ('', '')) + def test_getaddresses_nasty(self): eq = self.assertEqual eq(utils.getaddresses(['foo: ;']), [('', '')]) - eq(utils.getaddresses( - ['[]*-- =~$']), - [('', ''), ('', ''), ('', '*--')]) + eq(utils.getaddresses(['[]*-- =~$']), [('', '')]) eq(utils.getaddresses( ['foo: ;', '"Jason R. Mastaler" ']), [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]) + eq(utils.getaddresses( + [r'Pete(A nice \) chap) ']), + [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]) + eq(utils.getaddresses( + ['(Empty list)(start)Undisclosed recipients :(nobody(I know))']), + [('', '')]) + eq(utils.getaddresses( + ['Mary <@machine.tld:mary@example.net>, , jdoe@test . example']), + [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]) + eq(utils.getaddresses( + ['John Doe ']), + [('John Doe (comment)', 'jdoe@machine.example')]) + eq(utils.getaddresses( + ['"Mary Smith: Personal Account" ']), + [('Mary Smith: Personal Account', 'smith@home.example')]) + eq(utils.getaddresses( + ['Undisclosed recipients:;']), + [('', '')]) + eq(utils.getaddresses( + [r', "Giant; \"Big\" Box" ']), + [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]) def test_getaddresses_embedded_comment(self): """Test proper handling of a nested comment""" diff --git a/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst new file mode 100644 index 00000000000000..e0434ccd2ccab5 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-06-13-20-52-24.gh-issue-102988.Kei7Vf.rst @@ -0,0 +1,4 @@ +CVE-2023-27043: Prevent :func:`email.utils.parseaddr` +and :func:`email.utils.getaddresses` from returning the realname portion of an +invalid RFC2822 email header in the email address portion of the 2-tuple +returned after being parsed by :class:`email._parseaddr.AddressList`. From 22988c323ad621b9f47b6cb640b80ac806e26368 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 10 Jul 2023 16:04:26 -0700 Subject: [PATCH 338/446] gh-106529: Implement POP_JUMP_IF_XXX uops (#106551) - Hand-written uops JUMP_IF_{TRUE,FALSE}. These peek at the top of the stack. The jump target (in superblock space) is absolute. - Hand-written translation for POP_JUMP_IF_{TRUE,FALSE}, assuming the jump is unlikely. Once we implement jump-likelihood profiling, we can implement the jump-unlikely case (in another PR). - Tests (including some test cleanup). - Improvements to len(ex) and ex[i] to expose the whole trace. --- Lib/test/test_capi/test_misc.py | 63 +++++++++----- Python/ceval.c | 22 ++++- Python/opcode_metadata.h | 52 ++++++----- Python/optimizer.c | 111 ++++++++++++++++++------ Tools/cases_generator/generate_cases.py | 5 ++ 5 files changed, 181 insertions(+), 72 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 5f39f23401c3f2..fd27bd06097f6a 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2347,11 +2347,12 @@ def func(): @contextlib.contextmanager def temporary_optimizer(opt): + old_opt = _testinternalcapi.get_optimizer() _testinternalcapi.set_optimizer(opt) try: yield finally: - _testinternalcapi.set_optimizer(None) + _testinternalcapi.set_optimizer(old_opt) @contextlib.contextmanager @@ -2420,8 +2421,8 @@ def long_loop(): self.assertEqual(opt.get_count(), 10) - -def get_first_executor(code): +def get_first_executor(func): + code = func.__code__ co_code = code.co_code JUMP_BACKWARD = opcode.opmap["JUMP_BACKWARD"] for i in range(0, len(co_code), 2): @@ -2446,13 +2447,7 @@ def testfunc(x): with temporary_optimizer(opt): testfunc(1000) - ex = None - for offset in range(0, len(testfunc.__code__.co_code), 2): - try: - ex = _testinternalcapi.get_executor(testfunc.__code__, offset) - break - except ValueError: - pass + ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _ in ex} self.assertIn("SAVE_IP", uops) @@ -2493,11 +2488,13 @@ def many_vars(): opt = _testinternalcapi.get_uop_optimizer() with temporary_optimizer(opt): - ex = get_first_executor(many_vars.__code__) + ex = get_first_executor(many_vars) self.assertIsNone(ex) many_vars() - ex = get_first_executor(many_vars.__code__) - self.assertIn(("LOAD_FAST", 259), list(ex)) + + ex = get_first_executor(many_vars) + self.assertIsNotNone(ex) + self.assertIn(("LOAD_FAST", 259), list(ex)) def test_unspecialized_unpack(self): # An example of an unspecialized opcode @@ -2516,17 +2513,43 @@ def testfunc(x): with temporary_optimizer(opt): testfunc(10) - ex = None - for offset in range(0, len(testfunc.__code__.co_code), 2): - try: - ex = _testinternalcapi.get_executor(testfunc.__code__, offset) - break - except ValueError: - pass + ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = {opname for opname, _ in ex} self.assertIn("UNPACK_SEQUENCE", uops) + def test_pop_jump_if_false(self): + def testfunc(n): + i = 0 + while i < n: + i += 1 + + opt = _testinternalcapi.get_uop_optimizer() + + with temporary_optimizer(opt): + testfunc(10) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("_POP_JUMP_IF_FALSE", uops) + + def test_pop_jump_if_true(self): + def testfunc(n): + i = 0 + while not i >= n: + i += 1 + + opt = _testinternalcapi.get_uop_optimizer() + + with temporary_optimizer(opt): + testfunc(10) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("_POP_JUMP_IF_TRUE", uops) + if __name__ == "__main__": unittest.main() diff --git a/Python/ceval.c b/Python/ceval.c index da1135549a255c..866acd2dd69c7e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2751,7 +2751,8 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject operand = self->trace[pc].operand; oparg = (int)operand; DPRINTF(3, - " uop %s, operand %" PRIu64 ", stack_level %d\n", + "%4d: uop %s, operand %" PRIu64 ", stack_level %d\n", + pc, opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode], operand, (int)(stack_pointer - _PyFrame_Stackbase(frame))); @@ -2763,6 +2764,25 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject #define ENABLE_SPECIALIZATION 0 #include "executor_cases.c.h" + // NOTE: These pop-jumps move the uop pc, not the bytecode ip + case _POP_JUMP_IF_FALSE: + { + if (Py_IsFalse(stack_pointer[-1])) { + pc = oparg; + } + stack_pointer--; + break; + } + + case _POP_JUMP_IF_TRUE: + { + if (Py_IsTrue(stack_pointer[-1])) { + pc = oparg; + } + stack_pointer--; + break; + } + case SAVE_IP: { frame->prev_instr = ip_offset + oparg; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 92768e60f62ab0..64923e61fa4590 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -21,18 +21,20 @@ #define EXIT_TRACE 300 #define SAVE_IP 301 -#define _GUARD_BOTH_INT 302 -#define _BINARY_OP_MULTIPLY_INT 303 -#define _BINARY_OP_ADD_INT 304 -#define _BINARY_OP_SUBTRACT_INT 305 -#define _GUARD_BOTH_FLOAT 306 -#define _BINARY_OP_MULTIPLY_FLOAT 307 -#define _BINARY_OP_ADD_FLOAT 308 -#define _BINARY_OP_SUBTRACT_FLOAT 309 -#define _GUARD_BOTH_UNICODE 310 -#define _BINARY_OP_ADD_UNICODE 311 -#define _LOAD_LOCALS 312 -#define _LOAD_FROM_DICT_OR_GLOBALS 313 +#define _POP_JUMP_IF_FALSE 302 +#define _POP_JUMP_IF_TRUE 303 +#define _GUARD_BOTH_INT 304 +#define _BINARY_OP_MULTIPLY_INT 305 +#define _BINARY_OP_ADD_INT 306 +#define _BINARY_OP_SUBTRACT_INT 307 +#define _GUARD_BOTH_FLOAT 308 +#define _BINARY_OP_MULTIPLY_FLOAT 309 +#define _BINARY_OP_ADD_FLOAT 310 +#define _BINARY_OP_SUBTRACT_FLOAT 311 +#define _GUARD_BOTH_UNICODE 312 +#define _BINARY_OP_ADD_UNICODE 313 +#define _LOAD_LOCALS 314 +#define _LOAD_FROM_DICT_OR_GLOBALS 315 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1294,18 +1296,20 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { const char * const _PyOpcode_uop_name[512] = { [300] = "EXIT_TRACE", [301] = "SAVE_IP", - [302] = "_GUARD_BOTH_INT", - [303] = "_BINARY_OP_MULTIPLY_INT", - [304] = "_BINARY_OP_ADD_INT", - [305] = "_BINARY_OP_SUBTRACT_INT", - [306] = "_GUARD_BOTH_FLOAT", - [307] = "_BINARY_OP_MULTIPLY_FLOAT", - [308] = "_BINARY_OP_ADD_FLOAT", - [309] = "_BINARY_OP_SUBTRACT_FLOAT", - [310] = "_GUARD_BOTH_UNICODE", - [311] = "_BINARY_OP_ADD_UNICODE", - [312] = "_LOAD_LOCALS", - [313] = "_LOAD_FROM_DICT_OR_GLOBALS", + [302] = "_POP_JUMP_IF_FALSE", + [303] = "_POP_JUMP_IF_TRUE", + [304] = "_GUARD_BOTH_INT", + [305] = "_BINARY_OP_MULTIPLY_INT", + [306] = "_BINARY_OP_ADD_INT", + [307] = "_BINARY_OP_SUBTRACT_INT", + [308] = "_GUARD_BOTH_FLOAT", + [309] = "_BINARY_OP_MULTIPLY_FLOAT", + [310] = "_BINARY_OP_ADD_FLOAT", + [311] = "_BINARY_OP_SUBTRACT_FLOAT", + [312] = "_GUARD_BOTH_UNICODE", + [313] = "_BINARY_OP_ADD_UNICODE", + [314] = "_LOAD_LOCALS", + [315] = "_LOAD_FROM_DICT_OR_GLOBALS", }; #endif // NEED_OPCODE_METADATA #endif diff --git a/Python/optimizer.c b/Python/optimizer.c index 1d731ed2309c3c..48c29f55bee46b 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -307,7 +307,7 @@ uop_dealloc(_PyUOpExecutorObject *self) { static const char * uop_name(int index) { - if (index < EXIT_TRACE) { + if (index < 256) { return _PyOpcode_OpName[index]; } return _PyOpcode_uop_name[index]; @@ -316,9 +316,9 @@ uop_name(int index) { static Py_ssize_t uop_len(_PyUOpExecutorObject *self) { - int count = 1; + int count = 0; for (; count < _Py_UOP_MAX_TRACE_LENGTH; count++) { - if (self->trace[count-1].opcode == EXIT_TRACE) { + if (self->trace[count].opcode == 0) { break; } } @@ -328,28 +328,26 @@ uop_len(_PyUOpExecutorObject *self) static PyObject * uop_item(_PyUOpExecutorObject *self, Py_ssize_t index) { - for (int i = 0; i < _Py_UOP_MAX_TRACE_LENGTH; i++) { - if (self->trace[i].opcode == EXIT_TRACE) { - break; - } - if (i != index) { - continue; - } - const char *name = uop_name(self->trace[i].opcode); - PyObject *oname = _PyUnicode_FromASCII(name, strlen(name)); - if (oname == NULL) { - return NULL; - } - PyObject *operand = PyLong_FromUnsignedLongLong(self->trace[i].operand); - if (operand == NULL) { - Py_DECREF(oname); - return NULL; - } - PyObject *args[2] = { oname, operand }; - return _PyTuple_FromArraySteal(args, 2); + Py_ssize_t len = uop_len(self); + if (index < 0 || index >= len) { + PyErr_SetNone(PyExc_IndexError); + return NULL; } - PyErr_SetNone(PyExc_IndexError); - return NULL; + const char *name = uop_name(self->trace[index].opcode); + if (name == NULL) { + name = ""; + } + PyObject *oname = _PyUnicode_FromASCII(name, strlen(name)); + if (oname == NULL) { + return NULL; + } + PyObject *operand = PyLong_FromUnsignedLongLong(self->trace[index].operand); + if (operand == NULL) { + Py_DECREF(oname); + return NULL; + } + PyObject *args[2] = { oname, operand }; + return _PyTuple_FromArraySteal(args, 2); } PySequenceMethods uop_as_sequence = { @@ -372,12 +370,13 @@ translate_bytecode_to_trace( PyCodeObject *code, _Py_CODEUNIT *instr, _PyUOpInstruction *trace, - int max_length) + int buffer_size) { #ifdef Py_DEBUG _Py_CODEUNIT *initial_instr = instr; #endif int trace_length = 0; + int max_length = buffer_size; #ifdef Py_DEBUG char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); @@ -401,6 +400,14 @@ translate_bytecode_to_trace( trace[trace_length].operand = (OPERAND); \ trace_length++; +#define ADD_TO_STUB(INDEX, OPCODE, OPERAND) \ + DPRINTF(2, " ADD_TO_STUB(%d, %s, %" PRIu64 ")\n", \ + (INDEX), \ + (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)], \ + (uint64_t)(OPERAND)); \ + trace[(INDEX)].opcode = (OPCODE); \ + trace[(INDEX)].operand = (OPERAND); + DPRINTF(4, "Optimizing %s (%s:%d) at byte offset %ld\n", PyUnicode_AsUTF8(code->co_qualname), @@ -409,7 +416,7 @@ translate_bytecode_to_trace( 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive)); for (;;) { - ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + ADD_TO_TRACE(SAVE_IP, instr - (_Py_CODEUNIT *)code->co_code_adaptive); int opcode = instr->op.code; int oparg = instr->op.arg; int extras = 0; @@ -420,12 +427,35 @@ translate_bytecode_to_trace( oparg = (oparg << 8) | instr->op.arg; } if (opcode == ENTER_EXECUTOR) { - _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; + _PyExecutorObject *executor = + (_PyExecutorObject *)code->co_executors->executors[oparg&255]; opcode = executor->vm_data.opcode; DPRINTF(2, " * ENTER_EXECUTOR -> %s\n", _PyOpcode_OpName[opcode]); oparg = (oparg & 0xffffff00) | executor->vm_data.oparg; } switch (opcode) { + + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + { + // Assume jump unlikely (TODO: handle jump likely case) + // Reserve 5 entries (1 here, 2 stub, plus SAVE_IP + EXIT_TRACE) + if (trace_length + 5 > max_length) { + DPRINTF(1, "Ran out of space for POP_JUMP_IF_FALSE\n"); + goto done; + } + _Py_CODEUNIT *target_instr = + instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg; + max_length -= 2; // Really the start of the stubs + int uopcode = opcode == POP_JUMP_IF_TRUE ? + _POP_JUMP_IF_TRUE : _POP_JUMP_IF_FALSE; + ADD_TO_TRACE(uopcode, max_length); + ADD_TO_STUB(max_length, SAVE_IP, + target_instr - (_Py_CODEUNIT *)code->co_code_adaptive); + ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0); + break; + } + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -503,6 +533,30 @@ translate_bytecode_to_trace( code->co_firstlineno, 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive), trace_length); + if (max_length < buffer_size && trace_length < max_length) { + // Move the stubs back to be immediately after the main trace + // (which ends at trace_length) + DPRINTF(2, + "Moving %d stub uops back by %d\n", + buffer_size - max_length, + max_length - trace_length); + memmove(trace + trace_length, + trace + max_length, + (buffer_size - max_length) * sizeof(_PyUOpInstruction)); + // Patch up the jump targets + for (int i = 0; i < trace_length; i++) { + if (trace[i].opcode == _POP_JUMP_IF_FALSE || + trace[i].opcode == _POP_JUMP_IF_TRUE) + { + int target = trace[i].operand; + if (target >= max_length) { + target += trace_length - max_length; + trace[i].operand = target; + } + } + } + trace_length += buffer_size - max_length; + } return trace_length; } else { @@ -539,6 +593,9 @@ uop_optimize( } executor->base.execute = _PyUopExecute; memcpy(executor->trace, trace, trace_length * sizeof(_PyUOpInstruction)); + if (trace_length < _Py_UOP_MAX_TRACE_LENGTH) { + executor->trace[trace_length].opcode = 0; // Sentinel + } *exec_ptr = (_PyExecutorObject *)executor; return 1; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 14269ca8cbe750..932d0c14d398ab 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1338,12 +1338,17 @@ def write_pseudo_instrs(self) -> None: def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None: """Write '#define XXX NNN' for each uop""" counter = 300 # TODO: Avoid collision with pseudo instructions + def add(name: str) -> None: nonlocal counter self.out.emit(make_text(name, counter)) counter += 1 + add("EXIT_TRACE") add("SAVE_IP") + add("_POP_JUMP_IF_FALSE") + add("_POP_JUMP_IF_TRUE") + for instr in self.instrs.values(): if instr.kind == "op" and instr.is_viable_uop(): add(instr.name) From 115df8491a6633ced3cc3f2343b349869de30b8c Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Tue, 11 Jul 2023 10:14:53 +0900 Subject: [PATCH 339/446] gh-104635: Add a test case for variables that have a dependency. (gh-106583) --- Lib/test/test_compile.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 784c0550cc09b1..85ce0a4b39d854 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1186,6 +1186,15 @@ def f(x, y, z): return a self.assertEqual(f("x", "y", "z"), "y") + def test_variable_dependent(self): + # gh-104635: Since the value of b is dependent on the value of a + # the first STORE_FAST for a should not be skipped. (e.g POP_TOP). + # This test case is added to prevent potential regression from aggressive optimization. + def f(): + a = 42; b = a + 54; a = 54 + return a, b + self.assertEqual(f(), (54, 96)) + @requires_debug_ranges() class TestSourcePositions(unittest.TestCase): From 4bd8320dd7922d529eab51753dd524e8bf9c47b2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 10 Jul 2023 19:12:32 -0700 Subject: [PATCH 340/446] gh-106529: Silence compiler warning in jump target patching (#106613) (gh-106551 caused a compiler warning about on Windows.) --- Python/optimizer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index 48c29f55bee46b..08073193c0228f 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -548,8 +548,8 @@ translate_bytecode_to_trace( if (trace[i].opcode == _POP_JUMP_IF_FALSE || trace[i].opcode == _POP_JUMP_IF_TRUE) { - int target = trace[i].operand; - if (target >= max_length) { + uint64_t target = trace[i].operand; + if (target >= (uint64_t)max_length) { target += trace_length - max_length; trace[i].operand = target; } From e6379f72cbc60f6b3c5676f9e225d4f145d5693f Mon Sep 17 00:00:00 2001 From: Chris Withers Date: Tue, 11 Jul 2023 09:52:12 +0100 Subject: [PATCH 341/446] Remove unused branches from mock module (#106617) * lambda has a name of __none__, but no async lambda so this branch is not needed * _get_signature_object only returns None for bound builtins. There are no async builtins so this branch isn't needed * Exclude a couple of methods from coverage checking in the downstream rolling backport of mock --- Lib/test/test_unittest/testmock/testthreadingmock.py | 4 ++-- Lib/unittest/mock.py | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py index c6f179490d01f8..b6e12bcb3cda9c 100644 --- a/Lib/test/test_unittest/testmock/testthreadingmock.py +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -11,10 +11,10 @@ class Something: def method_1(self): - pass + pass # pragma: no cover def method_2(self): - pass + pass # pragma: no cover class TestThreadingMock(unittest.TestCase): diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 3ed54b3ba230ed..e8c8360e0ae13e 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -212,17 +212,12 @@ def _set_async_signature(mock, original, instance=False, is_async_mock=False): # signature as the original. skipfirst = isinstance(original, type) - result = _get_signature_object(original, instance, skipfirst) - if result is None: - return mock - func, sig = result + func, sig = _get_signature_object(original, instance, skipfirst) def checksig(*args, **kwargs): sig.bind(*args, **kwargs) _copy_func_details(func, checksig) name = original.__name__ - if not name.isidentifier(): - name = 'funcopy' context = {'_checksig_': checksig, 'mock': mock} src = """async def %s(*args, **kwargs): _checksig_(*args, **kwargs) From 1f2921b72c369b19c2e32aaedb9f8c63e0cb8b48 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 11 Jul 2023 11:38:22 +0200 Subject: [PATCH 342/446] gh-106572: Convert PyObject_DelAttr() to a function (#106611) * Convert PyObject_DelAttr() and PyObject_DelAttrString() macros to functions. * Add PyObject_DelAttr() and PyObject_DelAttrString() functions to the stable ABI. * Replace PyObject_SetAttr(obj, name, NULL) with PyObject_DelAttr(obj, name). --- Doc/data/stable_abi.dat | 2 ++ Include/abstract.h | 6 ++---- Include/object.h | 2 ++ Lib/test/test_stable_abi_ctypes.py | 2 ++ .../2023-07-11-01-07-39.gh-issue-106572.y1b35X.rst | 2 ++ Misc/stable_abi.toml | 4 ++++ Objects/object.c | 12 ++++++++++++ PC/python3dll.c | 2 ++ Python/bltinmodule.c | 3 ++- Python/bytecodes.c | 2 +- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 12 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-07-11-01-07-39.gh-issue-106572.y1b35X.rst diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 7fb002cd80369b..9a61ddc39a353f 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -490,6 +490,8 @@ function,PyObject_Calloc,3.7,, function,PyObject_CheckBuffer,3.11,, function,PyObject_ClearWeakRefs,3.2,, function,PyObject_CopyData,3.11,, +function,PyObject_DelAttr,3.13,, +function,PyObject_DelAttrString,3.13,, function,PyObject_DelItem,3.2,, function,PyObject_DelItemString,3.2,, function,PyObject_Dir,3.2,, diff --git a/Include/abstract.h b/Include/abstract.h index 016ace9bc89e96..c84d2c704e9605 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -80,7 +80,7 @@ extern "C" { This is the equivalent of the Python statement o.attr_name=v. */ -/* Implemented as a macro: +/* Implemented elsewhere: int PyObject_DelAttrString(PyObject *o, const char *attr_name); @@ -88,17 +88,15 @@ extern "C" { -1 on failure. This is the equivalent of the Python statement: del o.attr_name. */ -#define PyObject_DelAttrString(O, A) PyObject_SetAttrString((O), (A), NULL) -/* Implemented as a macro: +/* Implemented elsewhere: int PyObject_DelAttr(PyObject *o, PyObject *attr_name); Delete attribute named attr_name, for object o. Returns -1 on failure. This is the equivalent of the Python statement: del o.attr_name. */ -#define PyObject_DelAttr(O, A) PyObject_SetAttr((O), (A), NULL) /* Implemented elsewhere: diff --git a/Include/object.h b/Include/object.h index 3ef64511399c66..dccab07e5f2c6f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -391,9 +391,11 @@ PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *); PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); +PyAPI_FUNC(int) PyObject_DelAttrString(PyObject *v, const char *name); PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_DelAttr(PyObject *v, PyObject *name); PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 038c978e7bbd02..20bc2624c81361 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -509,6 +509,8 @@ def test_windows_feature_macros(self): "PyObject_CheckReadBuffer", "PyObject_ClearWeakRefs", "PyObject_CopyData", + "PyObject_DelAttr", + "PyObject_DelAttrString", "PyObject_DelItem", "PyObject_DelItemString", "PyObject_Dir", diff --git a/Misc/NEWS.d/next/C API/2023-07-11-01-07-39.gh-issue-106572.y1b35X.rst b/Misc/NEWS.d/next/C API/2023-07-11-01-07-39.gh-issue-106572.y1b35X.rst new file mode 100644 index 00000000000000..140e9fe7b9abf6 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-11-01-07-39.gh-issue-106572.y1b35X.rst @@ -0,0 +1,2 @@ +Convert :c:func:`PyObject_DelAttr` and :c:func:`PyObject_DelAttrString` +macros to functions. Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index bc7259f11816f3..c61fedf8390e28 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2432,3 +2432,7 @@ added = '3.13' [function.PyWeakref_GetRef] added = '3.13' +[function.PyObject_DelAttr] + added = '3.13' +[function.PyObject_DelAttrString] + added = '3.13' diff --git a/Objects/object.c b/Objects/object.c index c27b13e9e0c31a..540ba5d07427cd 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -942,6 +942,12 @@ PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) return res; } +int +PyObject_DelAttrString(PyObject *v, const char *name) +{ + return PyObject_SetAttrString(v, name, NULL); +} + int _PyObject_IsAbstract(PyObject *obj) { @@ -1185,6 +1191,12 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) return -1; } +int +PyObject_DelAttr(PyObject *v, PyObject *name) +{ + return PyObject_SetAttr(v, name, NULL); +} + PyObject ** _PyObject_ComputedDictPointer(PyObject *obj) { diff --git a/PC/python3dll.c b/PC/python3dll.c index 65bdf326ffbc7f..a7173911c7c1e8 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -447,6 +447,8 @@ EXPORT_FUNC(PyObject_CheckBuffer) EXPORT_FUNC(PyObject_CheckReadBuffer) EXPORT_FUNC(PyObject_ClearWeakRefs) EXPORT_FUNC(PyObject_CopyData) +EXPORT_FUNC(PyObject_DelAttr) +EXPORT_FUNC(PyObject_DelAttrString) EXPORT_FUNC(PyObject_DelItem) EXPORT_FUNC(PyObject_DelItemString) EXPORT_FUNC(PyObject_Dir) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 49efafc07f4245..20a86fc6f583d3 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -1567,8 +1567,9 @@ static PyObject * builtin_delattr_impl(PyObject *module, PyObject *obj, PyObject *name) /*[clinic end generated code: output=85134bc58dff79fa input=164865623abe7216]*/ { - if (PyObject_SetAttr(obj, name, (PyObject *)NULL) != 0) + if (PyObject_DelAttr(obj, name) < 0) { return NULL; + } Py_RETURN_NONE; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0848bbfd203ec4..88444293aa228b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1240,7 +1240,7 @@ dummy_func( inst(DELETE_ATTR, (owner --)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + int err = PyObject_DelAttr(owner, name); DECREF_INPUTS(); ERROR_IF(err, error); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index eccb30348173af..030d7ac15ef066 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1018,7 +1018,7 @@ PyObject *owner = stack_pointer[-1]; #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + int err = PyObject_DelAttr(owner, name); #line 1023 "Python/executor_cases.c.h" Py_DECREF(owner); #line 1245 "Python/bytecodes.c" diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 11823cf9cd293c..ecbf8ee59da1da 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1696,7 +1696,7 @@ PyObject *owner = stack_pointer[-1]; #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + int err = PyObject_DelAttr(owner, name); #line 1701 "Python/generated_cases.c.h" Py_DECREF(owner); #line 1245 "Python/bytecodes.c" From c0c041a31ba6a8d2da993a475a56b7d8211fdbf2 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 11 Jul 2023 11:33:59 +0100 Subject: [PATCH 343/446] GH-106529: Define POP_JUMP_IF_NONE in terms of POP_JUMP_IF_TRUE (GH-106599) --- Python/bytecodes.c | 16 +- Python/executor_cases.c.h | 114 ++++++----- Python/generated_cases.c.h | 374 ++++++++++++++++++++----------------- Python/opcode_metadata.h | 12 +- 4 files changed, 281 insertions(+), 235 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 88444293aa228b..3ba0d0f7e292f9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2282,22 +2282,20 @@ dummy_func( JUMPBY(oparg * Py_IsTrue(cond)); } - inst(POP_JUMP_IF_NOT_NONE, (value -- )) { - if (!Py_IsNone(value)) { - DECREF_INPUTS(); - JUMPBY(oparg); - } - } - - inst(POP_JUMP_IF_NONE, (value -- )) { + op(IS_NONE, (value -- b)) { if (Py_IsNone(value)) { - JUMPBY(oparg); + b = Py_True; } else { + b = Py_False; DECREF_INPUTS(); } } + macro(POP_JUMP_IF_NONE) = IS_NONE + POP_JUMP_IF_TRUE; + + macro(POP_JUMP_IF_NOT_NONE) = IS_NONE + POP_JUMP_IF_FALSE; + inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 030d7ac15ef066..ba854be7f6c05e 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1899,16 +1899,34 @@ break; } + case IS_NONE: { + PyObject *value = stack_pointer[-1]; + PyObject *b; + #line 2286 "Python/bytecodes.c" + if (Py_IsNone(value)) { + b = Py_True; + } + else { + b = Py_False; + #line 1912 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 2292 "Python/bytecodes.c" + } + #line 1916 "Python/executor_cases.c.h" + stack_pointer[-1] = b; + break; + } + case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2311 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1912 "Python/executor_cases.c.h" + #line 1930 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1919,16 +1937,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2319 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1928 "Python/executor_cases.c.h" + #line 1946 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2324 "Python/bytecodes.c" + #line 2322 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1936,7 +1954,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1940 "Python/executor_cases.c.h" + #line 1958 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1945,10 +1963,10 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2334 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1952 "Python/executor_cases.c.h" + #line 1970 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1957,10 +1975,10 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2339 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1964 "Python/executor_cases.c.h" + #line 1982 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1970,11 +1988,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2344 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1978 "Python/executor_cases.c.h" + #line 1996 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1983,14 +2001,14 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2350 "Python/bytecodes.c" + #line 2348 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1990 "Python/executor_cases.c.h" + #line 2008 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2353 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1994 "Python/executor_cases.c.h" + #line 2012 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1998,7 +2016,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2357 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2021,11 +2039,11 @@ if (iter == NULL) { goto error; } - #line 2025 "Python/executor_cases.c.h" + #line 2043 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2380 "Python/bytecodes.c" + #line 2378 "Python/bytecodes.c" } - #line 2029 "Python/executor_cases.c.h" + #line 2047 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -2035,7 +2053,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2612 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2056,7 +2074,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 2060 "Python/executor_cases.c.h" + #line 2078 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -2065,7 +2083,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2651 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2075,7 +2093,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 2079 "Python/executor_cases.c.h" + #line 2097 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2084,7 +2102,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3050 "Python/bytecodes.c" + #line 3048 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2092,7 +2110,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 2096 "Python/executor_cases.c.h" + #line 2114 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -2100,7 +2118,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3464 "Python/bytecodes.c" + #line 3462 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2112,7 +2130,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 2116 "Python/executor_cases.c.h" + #line 2134 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -2120,7 +2138,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3478 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2145,7 +2163,7 @@ default: Py_UNREACHABLE(); } - #line 2149 "Python/executor_cases.c.h" + #line 2167 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -2156,15 +2174,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3528 "Python/bytecodes.c" + #line 3526 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 2162 "Python/executor_cases.c.h" + #line 2180 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3530 "Python/bytecodes.c" + #line 3528 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 2168 "Python/executor_cases.c.h" + #line 2186 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -2174,14 +2192,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3534 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 2185 "Python/executor_cases.c.h" + #line 2203 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -2189,7 +2207,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3543 "Python/bytecodes.c" + #line 3541 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2200,7 +2218,7 @@ else { res = value; } - #line 2204 "Python/executor_cases.c.h" + #line 2222 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -2209,12 +2227,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3556 "Python/bytecodes.c" + #line 3554 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 2218 "Python/executor_cases.c.h" + #line 2236 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2223,10 +2241,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3563 "Python/bytecodes.c" + #line 3561 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 2230 "Python/executor_cases.c.h" + #line 2248 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -2237,7 +2255,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3568 "Python/bytecodes.c" + #line 3566 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2252,12 +2270,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 2256 "Python/executor_cases.c.h" + #line 2274 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3583 "Python/bytecodes.c" + #line 3581 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2261 "Python/executor_cases.c.h" + #line 2279 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2266,9 +2284,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3588 "Python/bytecodes.c" + #line 3586 "Python/bytecodes.c" assert(oparg >= 2); - #line 2272 "Python/executor_cases.c.h" + #line 2290 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ecbf8ee59da1da..325090a60f9d54 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3243,58 +3243,86 @@ DISPATCH(); } - TARGET(POP_JUMP_IF_NOT_NONE) { - PyObject *value = stack_pointer[-1]; - #line 2286 "Python/bytecodes.c" - if (!Py_IsNone(value)) { - #line 3251 "Python/generated_cases.c.h" - Py_DECREF(value); - #line 2288 "Python/bytecodes.c" - JUMPBY(oparg); + TARGET(POP_JUMP_IF_NONE) { + PyObject *_tmp_1 = stack_pointer[-1]; + { + PyObject *value = _tmp_1; + PyObject *b; + #line 2286 "Python/bytecodes.c" + if (Py_IsNone(value)) { + b = Py_True; + } + else { + b = Py_False; + #line 3258 "Python/generated_cases.c.h" + Py_DECREF(value); + #line 2292 "Python/bytecodes.c" + } + #line 3262 "Python/generated_cases.c.h" + _tmp_1 = b; + } + { + PyObject *cond = _tmp_1; + #line 2281 "Python/bytecodes.c" + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsTrue(cond)); + #line 3270 "Python/generated_cases.c.h" } - #line 3256 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } - TARGET(POP_JUMP_IF_NONE) { - PyObject *value = stack_pointer[-1]; - #line 2293 "Python/bytecodes.c" - if (Py_IsNone(value)) { - JUMPBY(oparg); + TARGET(POP_JUMP_IF_NOT_NONE) { + PyObject *_tmp_1 = stack_pointer[-1]; + { + PyObject *value = _tmp_1; + PyObject *b; + #line 2286 "Python/bytecodes.c" + if (Py_IsNone(value)) { + b = Py_True; + } + else { + b = Py_False; + #line 3287 "Python/generated_cases.c.h" + Py_DECREF(value); + #line 2292 "Python/bytecodes.c" + } + #line 3291 "Python/generated_cases.c.h" + _tmp_1 = b; } - else { - #line 3268 "Python/generated_cases.c.h" - Py_DECREF(value); - #line 2298 "Python/bytecodes.c" + { + PyObject *cond = _tmp_1; + #line 2276 "Python/bytecodes.c" + assert(PyBool_Check(cond)); + JUMPBY(oparg * Py_IsFalse(cond)); + #line 3299 "Python/generated_cases.c.h" } - #line 3272 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2302 "Python/bytecodes.c" + #line 2300 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3285 "Python/generated_cases.c.h" + #line 3313 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2311 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3298 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3305,16 +3333,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2319 "Python/bytecodes.c" + #line 2317 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3314 "Python/generated_cases.c.h" + #line 3342 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2324 "Python/bytecodes.c" + #line 2322 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3322,7 +3350,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3326 "Python/generated_cases.c.h" + #line 3354 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3331,10 +3359,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2334 "Python/bytecodes.c" + #line 2332 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3338 "Python/generated_cases.c.h" + #line 3366 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3343,10 +3371,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2339 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3350 "Python/generated_cases.c.h" + #line 3378 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3356,11 +3384,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2344 "Python/bytecodes.c" + #line 2342 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3364 "Python/generated_cases.c.h" + #line 3392 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3369,14 +3397,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2350 "Python/bytecodes.c" + #line 2348 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3376 "Python/generated_cases.c.h" + #line 3404 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2353 "Python/bytecodes.c" + #line 2351 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3380 "Python/generated_cases.c.h" + #line 3408 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3384,7 +3412,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2357 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3407,11 +3435,11 @@ if (iter == NULL) { goto error; } - #line 3411 "Python/generated_cases.c.h" + #line 3439 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2380 "Python/bytecodes.c" + #line 2378 "Python/bytecodes.c" } - #line 3415 "Python/generated_cases.c.h" + #line 3443 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3421,7 +3449,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2398 "Python/bytecodes.c" + #line 2396 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3453,7 +3481,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3457 "Python/generated_cases.c.h" + #line 3485 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3461,7 +3489,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2432 "Python/bytecodes.c" + #line 2430 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3487,14 +3515,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3491 "Python/generated_cases.c.h" + #line 3519 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2460 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3515,7 +3543,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3519 "Python/generated_cases.c.h" + #line 3547 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3525,7 +3553,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2483 "Python/bytecodes.c" + #line 2481 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3546,7 +3574,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3550 "Python/generated_cases.c.h" + #line 3578 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3556,7 +3584,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2506 "Python/bytecodes.c" + #line 2504 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3575,7 +3603,7 @@ if (next == NULL) { goto error; } - #line 3579 "Python/generated_cases.c.h" + #line 3607 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3584,7 +3612,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2527 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3600,14 +3628,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3604 "Python/generated_cases.c.h" + #line 3632 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2545 "Python/bytecodes.c" + #line 2543 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3630,16 +3658,16 @@ Py_DECREF(enter); goto error; } - #line 3634 "Python/generated_cases.c.h" + #line 3662 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2568 "Python/bytecodes.c" + #line 2566 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3643 "Python/generated_cases.c.h" + #line 3671 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3650,7 +3678,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2577 "Python/bytecodes.c" + #line 2575 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3676,16 +3704,16 @@ Py_DECREF(enter); goto error; } - #line 3680 "Python/generated_cases.c.h" + #line 3708 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2603 "Python/bytecodes.c" + #line 2601 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3689 "Python/generated_cases.c.h" + #line 3717 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3697,7 +3725,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2612 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3718,7 +3746,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3722 "Python/generated_cases.c.h" + #line 3750 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3727,7 +3755,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2651 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3737,7 +3765,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3741 "Python/generated_cases.c.h" + #line 3769 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3751,7 +3779,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2663 "Python/bytecodes.c" + #line 2661 "Python/bytecodes.c" assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); @@ -3768,7 +3796,7 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - #line 3772 "Python/generated_cases.c.h" + #line 3800 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3782,7 +3810,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2682 "Python/bytecodes.c" + #line 2680 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3792,7 +3820,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3796 "Python/generated_cases.c.h" + #line 3824 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3807,7 +3835,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2694 "Python/bytecodes.c" + #line 2692 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3820,11 +3848,11 @@ keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3824 "Python/generated_cases.c.h" + #line 3852 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2707 "Python/bytecodes.c" + #line 2705 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3828 "Python/generated_cases.c.h" + #line 3856 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3838,7 +3866,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2711 "Python/bytecodes.c" + #line 2709 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3846,11 +3874,11 @@ assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3850 "Python/generated_cases.c.h" + #line 3878 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2719 "Python/bytecodes.c" + #line 2717 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3854 "Python/generated_cases.c.h" + #line 3882 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3864,7 +3892,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2723 "Python/bytecodes.c" + #line 2721 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3878,7 +3906,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3882 "Python/generated_cases.c.h" + #line 3910 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3887,16 +3915,16 @@ } TARGET(KW_NAMES) { - #line 2739 "Python/bytecodes.c" + #line 2737 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3895 "Python/generated_cases.c.h" + #line 3923 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2745 "Python/bytecodes.c" + #line 2743 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3909,7 +3937,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3913 "Python/generated_cases.c.h" + #line 3941 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3919,7 +3947,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2791 "Python/bytecodes.c" + #line 2789 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4001,7 +4029,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4005 "Python/generated_cases.c.h" + #line 4033 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4013,7 +4041,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2879 "Python/bytecodes.c" + #line 2877 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -4023,7 +4051,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 4027 "Python/generated_cases.c.h" + #line 4055 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -4032,7 +4060,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2891 "Python/bytecodes.c" + #line 2889 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4058,7 +4086,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4062 "Python/generated_cases.c.h" + #line 4090 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4066,7 +4094,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2919 "Python/bytecodes.c" + #line 2917 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4102,7 +4130,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4106 "Python/generated_cases.c.h" + #line 4134 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4110,7 +4138,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2957 "Python/bytecodes.c" + #line 2955 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4120,7 +4148,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4124 "Python/generated_cases.c.h" + #line 4152 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4133,7 +4161,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2969 "Python/bytecodes.c" + #line 2967 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4144,7 +4172,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4148 "Python/generated_cases.c.h" + #line 4176 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4158,7 +4186,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2983 "Python/bytecodes.c" + #line 2981 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4169,7 +4197,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4173 "Python/generated_cases.c.h" + #line 4201 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4182,7 +4210,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2997 "Python/bytecodes.c" + #line 2995 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4233,12 +4261,12 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4237 "Python/generated_cases.c.h" + #line 4265 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3050 "Python/bytecodes.c" + #line 3048 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4246,7 +4274,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4250 "Python/generated_cases.c.h" + #line 4278 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4256,7 +4284,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3060 "Python/bytecodes.c" + #line 3058 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4278,7 +4306,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4282 "Python/generated_cases.c.h" + #line 4310 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4292,7 +4320,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3085 "Python/bytecodes.c" + #line 3083 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4320,7 +4348,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4324 "Python/generated_cases.c.h" + #line 4352 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4334,7 +4362,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3116 "Python/bytecodes.c" + #line 3114 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4366,7 +4394,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4370 "Python/generated_cases.c.h" + #line 4398 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4380,7 +4408,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3151 "Python/bytecodes.c" + #line 3149 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4412,7 +4440,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4416 "Python/generated_cases.c.h" + #line 4444 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4426,7 +4454,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3186 "Python/bytecodes.c" + #line 3184 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4451,7 +4479,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4455 "Python/generated_cases.c.h" + #line 4483 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4464,7 +4492,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3213 "Python/bytecodes.c" + #line 3211 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4491,7 +4519,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4495 "Python/generated_cases.c.h" + #line 4523 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4503,7 +4531,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3243 "Python/bytecodes.c" + #line 3241 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4521,14 +4549,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4525 "Python/generated_cases.c.h" + #line 4553 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3263 "Python/bytecodes.c" + #line 3261 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4559,7 +4587,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4563 "Python/generated_cases.c.h" + #line 4591 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4572,7 +4600,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3297 "Python/bytecodes.c" + #line 3295 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4601,7 +4629,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4605 "Python/generated_cases.c.h" + #line 4633 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4614,7 +4642,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3329 "Python/bytecodes.c" + #line 3327 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4643,7 +4671,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4647 "Python/generated_cases.c.h" + #line 4675 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4656,7 +4684,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3361 "Python/bytecodes.c" + #line 3359 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4684,7 +4712,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4688 "Python/generated_cases.c.h" + #line 4716 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4694,9 +4722,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3392 "Python/bytecodes.c" + #line 3390 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4700 "Python/generated_cases.c.h" + #line 4728 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4705,7 +4733,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3396 "Python/bytecodes.c" + #line 3394 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4767,14 +4795,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4771 "Python/generated_cases.c.h" + #line 4799 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3458 "Python/bytecodes.c" + #line 3456 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4778 "Python/generated_cases.c.h" + #line 4806 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4785,7 +4813,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3464 "Python/bytecodes.c" + #line 3462 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4797,7 +4825,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4801 "Python/generated_cases.c.h" + #line 4829 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4805,7 +4833,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3478 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4830,14 +4858,14 @@ default: Py_UNREACHABLE(); } - #line 4834 "Python/generated_cases.c.h" + #line 4862 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3505 "Python/bytecodes.c" + #line 3503 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4858,7 +4886,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4862 "Python/generated_cases.c.h" + #line 4890 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4866,15 +4894,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3528 "Python/bytecodes.c" + #line 3526 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4872 "Python/generated_cases.c.h" + #line 4900 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3530 "Python/bytecodes.c" + #line 3528 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4878 "Python/generated_cases.c.h" + #line 4906 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4884,14 +4912,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3534 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4895 "Python/generated_cases.c.h" + #line 4923 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4899,7 +4927,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3543 "Python/bytecodes.c" + #line 3541 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4910,7 +4938,7 @@ else { res = value; } - #line 4914 "Python/generated_cases.c.h" + #line 4942 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4919,12 +4947,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3556 "Python/bytecodes.c" + #line 3554 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4928 "Python/generated_cases.c.h" + #line 4956 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4933,10 +4961,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3563 "Python/bytecodes.c" + #line 3561 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4940 "Python/generated_cases.c.h" + #line 4968 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4948,7 +4976,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3568 "Python/bytecodes.c" + #line 3566 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4963,12 +4991,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4967 "Python/generated_cases.c.h" + #line 4995 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3583 "Python/bytecodes.c" + #line 3581 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4972 "Python/generated_cases.c.h" + #line 5000 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4978,16 +5006,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3588 "Python/bytecodes.c" + #line 3586 "Python/bytecodes.c" assert(oparg >= 2); - #line 4984 "Python/generated_cases.c.h" + #line 5012 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3592 "Python/bytecodes.c" + #line 3590 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4999,48 +5027,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 5003 "Python/generated_cases.c.h" + #line 5031 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3606 "Python/bytecodes.c" + #line 3604 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 5009 "Python/generated_cases.c.h" + #line 5037 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3610 "Python/bytecodes.c" + #line 3608 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 5017 "Python/generated_cases.c.h" + #line 5045 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3615 "Python/bytecodes.c" + #line 3613 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5028 "Python/generated_cases.c.h" + #line 5056 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3623 "Python/bytecodes.c" + #line 3621 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5039 "Python/generated_cases.c.h" + #line 5067 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3631 "Python/bytecodes.c" + #line 3629 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5052,12 +5080,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5056 "Python/generated_cases.c.h" + #line 5084 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3645 "Python/bytecodes.c" + #line 3643 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5069,30 +5097,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5073 "Python/generated_cases.c.h" + #line 5101 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3659 "Python/bytecodes.c" + #line 3657 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5084 "Python/generated_cases.c.h" + #line 5112 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3667 "Python/bytecodes.c" + #line 3665 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5091 "Python/generated_cases.c.h" + #line 5119 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3672 "Python/bytecodes.c" + #line 3670 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5098 "Python/generated_cases.c.h" + #line 5126 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 64923e61fa4590..ce2384ee2e4833 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -35,6 +35,7 @@ #define _BINARY_OP_ADD_UNICODE 313 #define _LOAD_LOCALS 314 #define _LOAD_FROM_DICT_OR_GLOBALS 315 +#define IS_NONE 316 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -328,10 +329,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case POP_JUMP_IF_TRUE: return 1; - case POP_JUMP_IF_NOT_NONE: - return 1; case POP_JUMP_IF_NONE: return 1; + case POP_JUMP_IF_NOT_NONE: + return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -772,10 +773,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_TRUE: return 0; - case POP_JUMP_IF_NOT_NONE: - return 0; case POP_JUMP_IF_NONE: return 0; + case POP_JUMP_IF_NOT_NONE: + return 0; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -1104,8 +1105,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, - [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG }, [GET_LEN] = { true, INSTR_FMT_IX, 0 }, [MATCH_CLASS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1310,6 +1311,7 @@ const char * const _PyOpcode_uop_name[512] = { [313] = "_BINARY_OP_ADD_UNICODE", [314] = "_LOAD_LOCALS", [315] = "_LOAD_FROM_DICT_OR_GLOBALS", + [316] = "IS_NONE", }; #endif // NEED_OPCODE_METADATA #endif From e5c32a811c248a9b052fc63236da58f81f488b44 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Tue, 11 Jul 2023 19:06:42 +0800 Subject: [PATCH 344/446] gh-106078: Move external C-API functions to decimal module global state (#106616) --- Modules/_decimal/_decimal.c | 47 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 6 --- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 89924b205f99e9..e3dc304066b45b 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -81,6 +81,14 @@ typedef struct { PyObject *Rational; PyObject *SignalTuple; + + /* External C-API functions */ + binaryfunc _py_long_multiply; + binaryfunc _py_long_floor_divide; + ternaryfunc _py_long_power; + unaryfunc _py_float_abs; + PyCFunction _py_long_bit_length; + PyCFunction _py_float_as_integer_ratio; } decimal_state; static decimal_state global_state; @@ -2299,14 +2307,6 @@ PyDecType_FromLongExact(PyTypeObject *type, PyObject *v, return dec; } -/* External C-API functions */ -static binaryfunc _py_long_multiply; -static binaryfunc _py_long_floor_divide; -static ternaryfunc _py_long_power; -static unaryfunc _py_float_abs; -static PyCFunction _py_long_bit_length; -static PyCFunction _py_float_as_integer_ratio; - /* Return a PyDecObject or a subtype from a PyFloatObject. Conversion is exact. */ static PyObject * @@ -2322,8 +2322,8 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, uint32_t status = 0; mpd_context_t maxctx; -#ifdef Py_DEBUG decimal_state *state = GLOBAL_STATE(); +#ifdef Py_DEBUG assert(PyType_IsSubtype(type, state->PyDec_Type)); #endif if (PyLong_Check(v)) { @@ -2358,13 +2358,13 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, } /* absolute value of the float */ - tmp = _py_float_abs(v); + tmp = state->_py_float_abs(v); if (tmp == NULL) { return NULL; } /* float as integer ratio: numerator/denominator */ - n_d = _py_float_as_integer_ratio(tmp, NULL); + n_d = state->_py_float_as_integer_ratio(tmp, NULL); Py_DECREF(tmp); if (n_d == NULL) { return NULL; @@ -2372,7 +2372,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, n = PyTuple_GET_ITEM(n_d, 0); d = PyTuple_GET_ITEM(n_d, 1); - tmp = _py_long_bit_length(d, NULL); + tmp = state->_py_long_bit_length(d, NULL); if (tmp == NULL) { Py_DECREF(n_d); return NULL; @@ -3660,14 +3660,14 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) goto error; } - Py_SETREF(exponent, _py_long_power(tmp, exponent, Py_None)); + Py_SETREF(exponent, state->_py_long_power(tmp, exponent, Py_None)); Py_DECREF(tmp); if (exponent == NULL) { goto error; } if (exp >= 0) { - Py_SETREF(numerator, _py_long_multiply(numerator, exponent)); + Py_SETREF(numerator, state->_py_long_multiply(numerator, exponent)); if (numerator == NULL) { goto error; } @@ -3683,12 +3683,12 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) if (tmp == NULL) { goto error; } - Py_SETREF(numerator, _py_long_floor_divide(numerator, tmp)); + Py_SETREF(numerator, state->_py_long_floor_divide(numerator, tmp)); if (numerator == NULL) { Py_DECREF(tmp); goto error; } - Py_SETREF(denominator, _py_long_floor_divide(denominator, tmp)); + Py_SETREF(denominator, state->_py_long_floor_divide(denominator, tmp)); Py_DECREF(tmp); if (denominator == NULL) { goto error; @@ -5834,13 +5834,14 @@ PyInit__decimal(void) decimal_state *state = GLOBAL_STATE(); /* Init external C-API functions */ - _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; - _py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; - _py_long_power = PyLong_Type.tp_as_number->nb_power; - _py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; - ASSIGN_PTR(_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type, - "as_integer_ratio")); - ASSIGN_PTR(_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length")); + state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; + state->_py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; + state->_py_long_power = PyLong_Type.tp_as_number->nb_power; + state->_py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; + ASSIGN_PTR(state->_py_float_as_integer_ratio, + cfunc_noargs(&PyFloat_Type, "as_integer_ratio")); + ASSIGN_PTR(state->_py_long_bit_length, + cfunc_noargs(&PyLong_Type, "bit_length")); /* Init types */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 38b47d06e4a5f9..90bbc8928b428a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -449,12 +449,6 @@ Modules/_cursesmodule.c - initialised - Modules/_cursesmodule.c - initialised_setupterm - Modules/_cursesmodule.c - initialisedcolors - Modules/_cursesmodule.c - screen_encoding - -Modules/_decimal/_decimal.c - _py_long_multiply - -Modules/_decimal/_decimal.c - _py_long_floor_divide - -Modules/_decimal/_decimal.c - _py_long_power - -Modules/_decimal/_decimal.c - _py_float_abs - -Modules/_decimal/_decimal.c - _py_long_bit_length - -Modules/_decimal/_decimal.c - _py_float_as_integer_ratio - Modules/_elementtree.c - expat_capi - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation - From af5cf1e75136fcef967d4ebe1bc45f29e6dc1bcf Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Tue, 11 Jul 2023 13:20:29 +0200 Subject: [PATCH 345/446] gh-103968: What's New: Add porting hints for PyType_From with metaclasses (GH-105698) --- Doc/whatsnew/3.12.rst | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 766f468cf9cfbc..a6d101bdb9f7a8 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1837,7 +1837,31 @@ Porting to Python 3.12 allowing incomplete initialization. Note that :c:func:`PyType_FromMetaclass` (added in Python 3.12) - already disallows creating classes whose metaclass overrides ``tp_new``. + already disallows creating classes whose metaclass overrides ``tp_new`` + (:meth:`~object.__new__` in Python). + + Since ``tp_new`` overrides almost everything ``PyType_From*`` functions do, + the two are incompatible with each other. + The existing behavior -- ignoring the metaclass for several steps + of type creation -- is unsafe in general, since (meta)classes assume that + ``tp_new`` was called. + There is no simple general workaround. One of the following may work for you: + + - If you control the metaclass, avoid using ``tp_new`` in it: + + - If initialization can be skipped, it can be done in + :c:member:`~PyTypeObject.tp_init` instead. + - If the metaclass doesn't need to be instantiated from Python, + set its ``tp_new`` to ``NULL`` using + the :const:`Py_TPFLAGS_DISALLOW_INSTANTIATION` flag. + This makes it acceptable for ``PyType_From*`` functions. + + - Avoid ``PyType_From*`` functions: if you don't need C-specific features + (slots or setting the instance size), create types by :ref:`calling ` + the metaclass. + + - If you *know* the ``tp_new`` can be skipped safely, filter the deprecation + warning out using :func:`warnings.catch_warnings` from Python. * :c:var:`PyOS_InputHook` and :c:var:`PyOS_ReadlineFunctionPointer` are no longer called in :ref:`subinterpreters `. This is From 95b7426f45edb570869a5513c142f29ed9f851a1 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Tue, 11 Jul 2023 04:35:54 -0700 Subject: [PATCH 346/446] gh-105497: [Enum] Fix flag mask inversion when unnamed flags exist (#106468) For example: class Flag(enum.Flag): A = 0x01 B = 0x02 MASK = 0xff ~Flag.MASK is Flag(0) --- Lib/enum.py | 8 +- Lib/test/test_enum.py | 138 +++++++++++------- ...-07-05-14-34-10.gh-issue-105497.HU5u89.rst | 1 + 3 files changed, 86 insertions(+), 61 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst diff --git a/Lib/enum.py b/Lib/enum.py index 47e31b17c2a495..202f0da028bdfe 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1515,14 +1515,10 @@ def __xor__(self, other): def __invert__(self): if self._inverted_ is None: - if self._boundary_ is KEEP: - # use all bits + if self._boundary_ in (EJECT, KEEP): self._inverted_ = self.__class__(~self._value_) else: - # use canonical bits (i.e. calculate flags not in this member) - self._inverted_ = self.__class__(self._singles_mask_ ^ self._value_) - if isinstance(self._inverted_, self.__class__): - self._inverted_._inverted_ = self + self._inverted_ = self.__class__(self._singles_mask_ & ~self._value_) return self._inverted_ __rand__ = __and__ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 54b7d18d454151..adb1e0e52c5485 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -818,6 +818,89 @@ def test_default_missing_with_wrong_type_value(self): self.MainEnum('RED') self.assertIs(ctx.exception.__context__, None) + def test_closed_invert_expectations(self): + class ClosedAB(self.enum_type): + A = 1 + B = 2 + MASK = 3 + A, B = ClosedAB + AB_MASK = ClosedAB.MASK + # + self.assertIs(~A, B) + self.assertIs(~B, A) + self.assertIs(~(A|B), ClosedAB(0)) + self.assertIs(~AB_MASK, ClosedAB(0)) + self.assertIs(~ClosedAB(0), (A|B)) + # + class ClosedXYZ(self.enum_type): + X = 4 + Y = 2 + Z = 1 + MASK = 7 + X, Y, Z = ClosedXYZ + XYZ_MASK = ClosedXYZ.MASK + # + self.assertIs(~X, Y|Z) + self.assertIs(~Y, X|Z) + self.assertIs(~Z, X|Y) + self.assertIs(~(X|Y), Z) + self.assertIs(~(X|Z), Y) + self.assertIs(~(Y|Z), X) + self.assertIs(~(X|Y|Z), ClosedXYZ(0)) + self.assertIs(~XYZ_MASK, ClosedXYZ(0)) + self.assertIs(~ClosedXYZ(0), (X|Y|Z)) + + def test_open_invert_expectations(self): + class OpenAB(self.enum_type): + A = 1 + B = 2 + MASK = 255 + A, B = OpenAB + AB_MASK = OpenAB.MASK + # + if OpenAB._boundary_ in (EJECT, KEEP): + self.assertIs(~A, OpenAB(254)) + self.assertIs(~B, OpenAB(253)) + self.assertIs(~(A|B), OpenAB(252)) + self.assertIs(~AB_MASK, OpenAB(0)) + self.assertIs(~OpenAB(0), AB_MASK) + else: + self.assertIs(~A, B) + self.assertIs(~B, A) + self.assertIs(~(A|B), OpenAB(0)) + self.assertIs(~AB_MASK, OpenAB(0)) + self.assertIs(~OpenAB(0), (A|B)) + # + class OpenXYZ(self.enum_type): + X = 4 + Y = 2 + Z = 1 + MASK = 31 + X, Y, Z = OpenXYZ + XYZ_MASK = OpenXYZ.MASK + # + if OpenXYZ._boundary_ in (EJECT, KEEP): + self.assertIs(~X, OpenXYZ(27)) + self.assertIs(~Y, OpenXYZ(29)) + self.assertIs(~Z, OpenXYZ(30)) + self.assertIs(~(X|Y), OpenXYZ(25)) + self.assertIs(~(X|Z), OpenXYZ(26)) + self.assertIs(~(Y|Z), OpenXYZ(28)) + self.assertIs(~(X|Y|Z), OpenXYZ(24)) + self.assertIs(~XYZ_MASK, OpenXYZ(0)) + self.assertTrue(~OpenXYZ(0), XYZ_MASK) + else: + self.assertIs(~X, Y|Z) + self.assertIs(~Y, X|Z) + self.assertIs(~Z, X|Y) + self.assertIs(~(X|Y), Z) + self.assertIs(~(X|Z), Y) + self.assertIs(~(Y|Z), X) + self.assertIs(~(X|Y|Z), OpenXYZ(0)) + self.assertIs(~XYZ_MASK, OpenXYZ(0)) + self.assertTrue(~OpenXYZ(0), (X|Y|Z)) + + class TestPlainEnum(_EnumTests, _PlainOutputTests, unittest.TestCase): enum_type = Enum @@ -3045,33 +3128,6 @@ class Color(Flag): WHITE = RED|GREEN|BLUE BLANCO = RED|GREEN|BLUE - class Complete(Flag): - A = 0x01 - B = 0x02 - - class Partial(Flag): - A = 0x01 - B = 0x02 - MASK = 0xff - - class CompleteInt(IntFlag): - A = 0x01 - B = 0x02 - - class PartialInt(IntFlag): - A = 0x01 - B = 0x02 - MASK = 0xff - - class CompleteIntStrict(IntFlag, boundary=STRICT): - A = 0x01 - B = 0x02 - - class PartialIntStrict(IntFlag, boundary=STRICT): - A = 0x01 - B = 0x02 - MASK = 0xff - def test_or(self): Perm = self.Perm for i in Perm: @@ -3115,34 +3171,6 @@ def test_xor(self): self.assertIs(Open.RO ^ Open.CE, Open.CE) self.assertIs(Open.CE ^ Open.CE, Open.RO) - def test_invert(self): - Perm = self.Perm - RW = Perm.R | Perm.W - RX = Perm.R | Perm.X - WX = Perm.W | Perm.X - RWX = Perm.R | Perm.W | Perm.X - values = list(Perm) + [RW, RX, WX, RWX, Perm(0)] - for i in values: - self.assertIs(type(~i), Perm) - self.assertEqual(~~i, i) - for i in Perm: - self.assertIs(~~i, i) - Open = self.Open - self.assertIs(Open.WO & ~Open.WO, Open.RO) - self.assertIs((Open.WO|Open.CE) & ~Open.WO, Open.CE) - Complete = self.Complete - self.assertIs(~Complete.A, Complete.B) - Partial = self.Partial - self.assertIs(~Partial.A, Partial.B) - CompleteInt = self.CompleteInt - self.assertIs(~CompleteInt.A, CompleteInt.B) - PartialInt = self.PartialInt - self.assertIs(~PartialInt.A, PartialInt(254)) - CompleteIntStrict = self.CompleteIntStrict - self.assertIs(~CompleteIntStrict.A, CompleteIntStrict.B) - PartialIntStrict = self.PartialIntStrict - self.assertIs(~PartialIntStrict.A, PartialIntStrict.B) - def test_bool(self): Perm = self.Perm for f in Perm: diff --git a/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst new file mode 100644 index 00000000000000..f4f2db08f73f50 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-05-14-34-10.gh-issue-105497.HU5u89.rst @@ -0,0 +1 @@ +Fix flag mask inversion when unnamed flags exist. From 388b5daa523b828dc0f7e2a1a6886bebc20833ba Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:41:50 +0300 Subject: [PATCH 347/446] gh-106360: remove redundant #ifdef (#106622) --- Python/opcode_metadata.h | 4 +--- Tools/cases_generator/generate_cases.py | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ce2384ee2e4833..34ac85d6517a88 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -960,7 +960,7 @@ struct opcode_macro_expansion { extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; extern const char * const _PyOpcode_uop_name[512]; -#else +#else // if NEED_OPCODE_METADATA const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1293,7 +1293,6 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; -#ifdef NEED_OPCODE_METADATA const char * const _PyOpcode_uop_name[512] = { [300] = "EXIT_TRACE", [301] = "SAVE_IP", @@ -1314,4 +1313,3 @@ const char * const _PyOpcode_uop_name[512] = { [316] = "IS_NONE", }; #endif // NEED_OPCODE_METADATA -#endif diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 932d0c14d398ab..641a327b06aa22 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1240,7 +1240,7 @@ def write_metadata(self) -> None: self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") self.out.emit("extern const char * const _PyOpcode_uop_name[512];") - self.out.emit("#else") + self.out.emit("#else // if NEED_OPCODE_METADATA") self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") @@ -1289,12 +1289,10 @@ def write_metadata(self) -> None: case _: typing.assert_never(thing) - self.out.emit("#ifdef NEED_OPCODE_METADATA") with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",") - self.out.emit("#endif // NEED_OPCODE_METADATA") - self.out.emit("#endif") + self.out.emit("#endif // NEED_OPCODE_METADATA") with open(self.pymetadata_filename, "w") as f: # Create formatter From 64c0890b697783db9b3f67e3bb4dcee1165a0b9b Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima Date: Tue, 11 Jul 2023 23:55:37 +0900 Subject: [PATCH 348/446] wasm: do not use inline comment in .editorconfig (#106610) It is no longer valid since 0.15.0 https://github.com/editorconfig/specification/blob/v0.15/index.rst#no-inline-comments --- Tools/wasm/.editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/wasm/.editorconfig b/Tools/wasm/.editorconfig index da1aa6acaccc7e..4de5fe5954d84b 100644 --- a/Tools/wasm/.editorconfig +++ b/Tools/wasm/.editorconfig @@ -1,4 +1,5 @@ -root = false # This extends the root .editorconfig +# This extends the root .editorconfig +root = false [*.{html,js}] trim_trailing_whitespace = true From a2d54d4e8ab12f967a220be88bde8ac8227c5ab3 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 11 Jul 2023 11:07:20 -0400 Subject: [PATCH 349/446] gh-106498: Revert incorrect colorsys.rgb_to_hls change (#106627) gh-86618 assumed a-b-c = a-(b+c) = a-d where d = b+d. For floats 2.0, 1.0, and 0.9999999999999999, this assumption is false. The net change of 1.1102230246251565e-16 to 0.0 results in division by 0. Revert the replacement. Add test. --- Lib/colorsys.py | 2 +- Lib/test/test_colorsys.py | 10 ++++++++++ .../2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst diff --git a/Lib/colorsys.py b/Lib/colorsys.py index 9bdc83e3772603..bc897bd0f99298 100644 --- a/Lib/colorsys.py +++ b/Lib/colorsys.py @@ -83,7 +83,7 @@ def rgb_to_hls(r, g, b): if l <= 0.5: s = rangec / sumc else: - s = rangec / (2.0-sumc) + s = rangec / (2.0-maxc-minc) # Not always 2.0-sumc: gh-106498. rc = (maxc-r) / rangec gc = (maxc-g) / rangec bc = (maxc-b) / rangec diff --git a/Lib/test/test_colorsys.py b/Lib/test/test_colorsys.py index a24e3adcb4b842..74d76294b0b4d4 100644 --- a/Lib/test/test_colorsys.py +++ b/Lib/test/test_colorsys.py @@ -69,6 +69,16 @@ def test_hls_values(self): self.assertTripleEqual(hls, colorsys.rgb_to_hls(*rgb)) self.assertTripleEqual(rgb, colorsys.hls_to_rgb(*hls)) + def test_hls_nearwhite(self): # gh-106498 + values = ( + # rgb, hls: these do not work in reverse + ((0.9999999999999999, 1, 1), (0.5, 1.0, 1.0)), + ((1, 0.9999999999999999, 0.9999999999999999), (0.0, 1.0, 1.0)), + ) + for rgb, hls in values: + self.assertTripleEqual(hls, colorsys.rgb_to_hls(*rgb)) + self.assertTripleEqual((1.0, 1.0, 1.0), colorsys.hls_to_rgb(*hls)) + def test_yiq_roundtrip(self): for r in frange(0.0, 1.0, 0.2): for g in frange(0.0, 1.0, 0.2): diff --git a/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst b/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst new file mode 100644 index 00000000000000..09fc647cc01d21 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-11-09-25-40.gh-issue-106530.VgXrMx.rst @@ -0,0 +1,2 @@ +Revert a change to :func:`colorsys.rgb_to_hls` that caused division by zero +for certain almost-white inputs. Patch by Terry Jan Reedy. From 945d3cbf2e8e756ed16c3ec51106e6157abb2698 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 11 Jul 2023 08:43:24 -0700 Subject: [PATCH 350/446] gh-106403: Restore weakref support for TypeVar and friends (#106418) --- Lib/test/test_type_params.py | 31 +++++++++++++++++++ ...-07-04-07-25-30.gh-issue-106403.GmefbV.rst | 4 +++ Objects/typevarobject.c | 12 ++++--- 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 3026cc22476619..bced641a9661fd 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -3,6 +3,7 @@ import types import unittest import pickle +import weakref from test.support import requires_working_socket, check_syntax_error, run_code from typing import Generic, Sequence, TypeVar, TypeVarTuple, ParamSpec, get_args @@ -921,3 +922,33 @@ def test_pickling_classes(self): # These instances are not equal, # but class check is good enough: self.assertIsInstance(pickle.loads(pickled), real_class) + + +class TypeParamsWeakRefTest(unittest.TestCase): + def test_weakrefs(self): + T = TypeVar('T') + P = ParamSpec('P') + class OldStyle(Generic[T]): + pass + + class NewStyle[T]: + pass + + cases = [ + T, + TypeVar('T', bound=int), + P, + P.args, + P.kwargs, + TypeVarTuple('Ts'), + OldStyle, + OldStyle[int], + OldStyle(), + NewStyle, + NewStyle[int], + NewStyle(), + Generic[T], + ] + for case in cases: + with self.subTest(case=case): + weakref.ref(case) diff --git a/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst new file mode 100644 index 00000000000000..4fea45f16c4f8e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-04-07-25-30.gh-issue-106403.GmefbV.rst @@ -0,0 +1,4 @@ +Instances of :class:`typing.TypeVar`, :class:`typing.ParamSpec`, +:class:`typing.ParamSpecArgs`, :class:`typing.ParamSpecKwargs`, and +:class:`typing.TypeVarTuple` once again support weak references, fixing a +regression introduced in Python 3.12.0 beta 1. Patch by Jelle Zijlstra. diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c index 0b44f84b6f01d2..5605662f0e6d5e 100644 --- a/Objects/typevarobject.c +++ b/Objects/typevarobject.c @@ -500,7 +500,7 @@ PyType_Spec typevar_spec = { .name = "typing.TypeVar", .basicsize = sizeof(typevarobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevar_slots, }; @@ -647,7 +647,8 @@ static PyType_Slot paramspecargs_slots[] = { PyType_Spec paramspecargs_spec = { .name = "typing.ParamSpecArgs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspecargs_slots, }; @@ -726,7 +727,8 @@ static PyType_Slot paramspeckwargs_slots[] = { PyType_Spec paramspeckwargs_spec = { .name = "typing.ParamSpecKwargs", .basicsize = sizeof(paramspecattrobject), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE + | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspeckwargs_slots, }; @@ -1007,7 +1009,7 @@ PyType_Spec paramspec_spec = { .name = "typing.ParamSpec", .basicsize = sizeof(paramspecobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE - | Py_TPFLAGS_MANAGED_DICT, + | Py_TPFLAGS_MANAGED_DICT | Py_TPFLAGS_MANAGED_WEAKREF, .slots = paramspec_slots, }; @@ -1228,7 +1230,7 @@ PyType_Spec typevartuple_spec = { .name = "typing.TypeVarTuple", .basicsize = sizeof(typevartupleobject), .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_MANAGED_DICT - | Py_TPFLAGS_HAVE_GC, + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_MANAGED_WEAKREF, .slots = typevartuple_slots, }; From d0b7e18262e69dd4b8252e804e4f98fc9533bcd6 Mon Sep 17 00:00:00 2001 From: RustyNail Date: Wed, 12 Jul 2023 02:22:07 +0900 Subject: [PATCH 351/446] gh-106625 : Add missing code to tutorial 4.6 example (#106623) * Added missing import statement. * Update Doc/tutorial/controlflow.rst * Update Doc/tutorial/controlflow.rst * Update controlflow.rst * Make point regular class with __init__. --------- Co-authored-by: Terry Jan Reedy --- Doc/tutorial/controlflow.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index c9b3d982c31c9a..4336bf50df40a7 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -307,8 +307,9 @@ you can use the class name followed by an argument list resembling a constructor, but with the ability to capture attributes into variables:: class Point: - x: int - y: int + def __init__(self, x, y): + self.x = x + self.y = y def where_is(point): match point: From 292ac4bfe92768140c2d383fd329cfa1949869b2 Mon Sep 17 00:00:00 2001 From: Kirill Podoprigora Date: Tue, 11 Jul 2023 21:04:09 +0300 Subject: [PATCH 352/446] gh-102541: Add test case for help() for non_existent_module (#106340) Test fix for when one enters, for instance, 'abd' at the 'help>' prompt. --------- Co-authored-by: Terry Jan Reedy --- Lib/test/test_pydoc.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 115ffd3c29d4d6..ddb5187f90da9b 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -24,7 +24,8 @@ from urllib.request import urlopen, urlcleanup from test.support import import_helper from test.support import os_helper -from test.support.script_helper import assert_python_ok, assert_python_failure +from test.support.script_helper import (assert_python_ok, + assert_python_failure, spawn_python) from test.support import threading_helper from test.support import (reap_children, captured_output, captured_stdout, captured_stderr, is_emscripten, is_wasi, @@ -631,6 +632,14 @@ def test_builtin_on_metaclasses(self): # Testing that the subclasses section does not appear self.assertNotIn('Built-in subclasses', text) + def test_fail_help_cli(self): + elines = (missing_pattern % 'abd').splitlines() + with spawn_python("-c" "help()") as proc: + out, _ = proc.communicate(b"abd") + olines = out.decode().splitlines()[-9:-6] + olines[0] = olines[0].removeprefix('help> ') + self.assertEqual(elines, olines) + def test_fail_help_output_redirect(self): with StringIO() as buf: helper = pydoc.Helper(output=buf) From cabd6e8a107127ff02f0b514148f648fb2472a58 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 11 Jul 2023 11:08:10 -0700 Subject: [PATCH 353/446] gh-106529: Support JUMP_BACKWARD in Tier 2 (uops) (#106543) During superblock generation, a JUMP_BACKWARD instruction is translated to either a JUMP_TO_TOP micro-op (when the target of the jump is exactly the beginning of the superblock, closing the loop), or a SAVE_IP + EXIT_TRACE pair, when the jump goes elsewhere. The new JUMP_TO_TOP instruction includes a CHECK_EVAL_BREAKER() call, so a closed loop can still be interrupted. --- Lib/test/test_capi/test_misc.py | 16 +++++++- Python/ceval.c | 7 ++++ Python/opcode_metadata.h | 54 +++++++++++++------------ Python/optimizer.c | 15 ++++++- Tools/cases_generator/generate_cases.py | 1 + 5 files changed, 63 insertions(+), 30 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index fd27bd06097f6a..9cbd5506bf6dea 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2525,7 +2525,6 @@ def testfunc(n): i += 1 opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): testfunc(10) @@ -2541,7 +2540,6 @@ def testfunc(n): i += 1 opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): testfunc(10) @@ -2550,6 +2548,20 @@ def testfunc(n): uops = {opname for opname, _ in ex} self.assertIn("_POP_JUMP_IF_TRUE", uops) + def test_jump_backward(self): + def testfunc(n): + i = 0 + while i < n: + i += 1 + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(10) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("JUMP_TO_TOP", uops) + if __name__ == "__main__": unittest.main() diff --git a/Python/ceval.c b/Python/ceval.c index 866acd2dd69c7e..57e478c1313f64 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2783,6 +2783,13 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject break; } + case JUMP_TO_TOP: + { + pc = 0; + CHECK_EVAL_BREAKER(); + break; + } + case SAVE_IP: { frame->prev_instr = ip_offset + oparg; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 34ac85d6517a88..4a41cd86a4287b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -23,19 +23,20 @@ #define SAVE_IP 301 #define _POP_JUMP_IF_FALSE 302 #define _POP_JUMP_IF_TRUE 303 -#define _GUARD_BOTH_INT 304 -#define _BINARY_OP_MULTIPLY_INT 305 -#define _BINARY_OP_ADD_INT 306 -#define _BINARY_OP_SUBTRACT_INT 307 -#define _GUARD_BOTH_FLOAT 308 -#define _BINARY_OP_MULTIPLY_FLOAT 309 -#define _BINARY_OP_ADD_FLOAT 310 -#define _BINARY_OP_SUBTRACT_FLOAT 311 -#define _GUARD_BOTH_UNICODE 312 -#define _BINARY_OP_ADD_UNICODE 313 -#define _LOAD_LOCALS 314 -#define _LOAD_FROM_DICT_OR_GLOBALS 315 -#define IS_NONE 316 +#define JUMP_TO_TOP 304 +#define _GUARD_BOTH_INT 305 +#define _BINARY_OP_MULTIPLY_INT 306 +#define _BINARY_OP_ADD_INT 307 +#define _BINARY_OP_SUBTRACT_INT 308 +#define _GUARD_BOTH_FLOAT 309 +#define _BINARY_OP_MULTIPLY_FLOAT 310 +#define _BINARY_OP_ADD_FLOAT 311 +#define _BINARY_OP_SUBTRACT_FLOAT 312 +#define _GUARD_BOTH_UNICODE 313 +#define _BINARY_OP_ADD_UNICODE 314 +#define _LOAD_LOCALS 315 +#define _LOAD_FROM_DICT_OR_GLOBALS 316 +#define IS_NONE 317 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1298,18 +1299,19 @@ const char * const _PyOpcode_uop_name[512] = { [301] = "SAVE_IP", [302] = "_POP_JUMP_IF_FALSE", [303] = "_POP_JUMP_IF_TRUE", - [304] = "_GUARD_BOTH_INT", - [305] = "_BINARY_OP_MULTIPLY_INT", - [306] = "_BINARY_OP_ADD_INT", - [307] = "_BINARY_OP_SUBTRACT_INT", - [308] = "_GUARD_BOTH_FLOAT", - [309] = "_BINARY_OP_MULTIPLY_FLOAT", - [310] = "_BINARY_OP_ADD_FLOAT", - [311] = "_BINARY_OP_SUBTRACT_FLOAT", - [312] = "_GUARD_BOTH_UNICODE", - [313] = "_BINARY_OP_ADD_UNICODE", - [314] = "_LOAD_LOCALS", - [315] = "_LOAD_FROM_DICT_OR_GLOBALS", - [316] = "IS_NONE", + [304] = "JUMP_TO_TOP", + [305] = "_GUARD_BOTH_INT", + [306] = "_BINARY_OP_MULTIPLY_INT", + [307] = "_BINARY_OP_ADD_INT", + [308] = "_BINARY_OP_SUBTRACT_INT", + [309] = "_GUARD_BOTH_FLOAT", + [310] = "_BINARY_OP_MULTIPLY_FLOAT", + [311] = "_BINARY_OP_ADD_FLOAT", + [312] = "_BINARY_OP_SUBTRACT_FLOAT", + [313] = "_GUARD_BOTH_UNICODE", + [314] = "_BINARY_OP_ADD_UNICODE", + [315] = "_LOAD_LOCALS", + [316] = "_LOAD_FROM_DICT_OR_GLOBALS", + [317] = "IS_NONE", }; #endif // NEED_OPCODE_METADATA diff --git a/Python/optimizer.c b/Python/optimizer.c index 08073193c0228f..8d4162b44c2f35 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -372,9 +372,7 @@ translate_bytecode_to_trace( _PyUOpInstruction *trace, int buffer_size) { -#ifdef Py_DEBUG _Py_CODEUNIT *initial_instr = instr; -#endif int trace_length = 0; int max_length = buffer_size; @@ -456,6 +454,19 @@ translate_bytecode_to_trace( break; } + case JUMP_BACKWARD: + { + if (instr + 2 - oparg == initial_instr + && trace_length + 3 <= max_length) + { + ADD_TO_TRACE(JUMP_TO_TOP, 0); + } + else { + DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n"); + } + goto done; + } + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 641a327b06aa22..8c77c1f08335df 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1346,6 +1346,7 @@ def add(name: str) -> None: add("SAVE_IP") add("_POP_JUMP_IF_FALSE") add("_POP_JUMP_IF_TRUE") + add("JUMP_TO_TOP") for instr in self.instrs.values(): if instr.kind == "op" and instr.is_viable_uop(): From 579aa89e68a6607398317a50586af781981e89fb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 11 Jul 2023 22:13:27 +0300 Subject: [PATCH 354/446] gh-106521: Add PyObject_GetOptionalAttr() function (GH-106522) It is a new name of former _PyObject_LookupAttr(). Add also PyObject_GetOptionalAttrString(). --- Doc/c-api/object.rst | 41 ++++++++++++++++++- Doc/data/stable_abi.dat | 2 + Doc/whatsnew/3.13.rst | 8 ++++ Include/abstract.h | 32 +++++++++++++++ Include/cpython/object.h | 12 +----- Include/object.h | 4 ++ Lib/test/test_stable_abi_ctypes.py | 2 + ...-07-07-19-14-00.gh-issue-106521.Veh9f3.rst | 1 + Misc/stable_abi.toml | 4 ++ Objects/object.c | 34 ++++++++++----- PC/python3dll.c | 2 + 11 files changed, 119 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-07-07-19-14-00.gh-issue-106521.Veh9f3.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 22e7458013fb3d..6fc5b2d14dd327 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -37,7 +37,8 @@ Object Protocol Exceptions that occur when this calls :meth:`~object.__getattr__` and :meth:`~object.__getattribute__` methods are silently ignored. - For proper error handling, use :c:func:`PyObject_GetAttr` instead. + For proper error handling, use :c:func:`PyObject_GetOptionalAttr` or + :c:func:`PyObject_GetAttr` instead. .. c:function:: int PyObject_HasAttrString(PyObject *o, const char *attr_name) @@ -51,7 +52,8 @@ Object Protocol Exceptions that occur when this calls :meth:`~object.__getattr__` and :meth:`~object.__getattribute__` methods or while creating the temporary :class:`str` object are silently ignored. - For proper error handling, use :c:func:`PyObject_GetAttrString` instead. + For proper error handling, use :c:func:`PyObject_GetOptionalAttrString` + or :c:func:`PyObject_GetAttrString` instead. .. c:function:: PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name) @@ -60,6 +62,9 @@ Object Protocol value on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``o.attr_name``. + If the missing attribute should not be treated as a failure, you can use + :c:func:`PyObject_GetOptionalAttr` instead. + .. c:function:: PyObject* PyObject_GetAttrString(PyObject *o, const char *attr_name) @@ -67,6 +72,38 @@ Object Protocol value on success, or ``NULL`` on failure. This is the equivalent of the Python expression ``o.attr_name``. + If the missing attribute should not be treated as a failure, you can use + :c:func:`PyObject_GetOptionalAttrString` instead. + + +.. c:function:: int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result); + + Variant of :c:func:`PyObject_GetAttr` which doesn't raise + :exc:`AttributeError` if the attribute is not found. + + If the attribute is found, return ``1`` and set *\*result* to a new + :term:`strong reference` to the attribute. + If the attribute is not found, return ``0`` and set *\*result* to ``NULL``; + the :exc:`AttributeError` is silenced. + If an error other than :exc:`AttributeError` is raised, return ``-1`` and + set *\*result* to ``NULL``. + + .. versionadded:: 3.13 + + +.. c:function:: int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result); + + Variant of :c:func:`PyObject_GetAttrString` which doesn't raise + :exc:`AttributeError` if the attribute is not found. + + If the attribute is found, return ``1`` and set *\*result* to a new + :term:`strong reference` to the attribute. + If the attribute is not found, return ``0`` and set *\*result* to ``NULL``; + the :exc:`AttributeError` is silenced. + If an error other than :exc:`AttributeError` is raised, return ``-1`` and + set *\*result* to ``NULL``. + + .. versionadded:: 3.13 .. c:function:: PyObject* PyObject_GenericGetAttr(PyObject *o, PyObject *name) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 9a61ddc39a353f..d7e8b5b464a71b 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -512,6 +512,8 @@ function,PyObject_GetAttrString,3.2,, function,PyObject_GetBuffer,3.11,, function,PyObject_GetItem,3.2,, function,PyObject_GetIter,3.2,, +function,PyObject_GetOptionalAttr,3.13,, +function,PyObject_GetOptionalAttrString,3.13,, function,PyObject_GetTypeData,3.12,, function,PyObject_HasAttr,3.2,, function,PyObject_HasAttrString,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 8fc809deca139b..62981673140cf7 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -734,6 +734,14 @@ New Features ``NULL`` if the referent is no longer live. (Contributed by Victor Stinner in :gh:`105927`.) +* Add :c:func:`PyObject_GetOptionalAttr` and + :c:func:`PyObject_GetOptionalAttrString`, variants of + :c:func:`PyObject_GetAttr` and :c:func:`PyObject_GetAttrString` which + don't raise :exc:`AttributeError` if the attribute is not found. + These variants are more convenient and faster if the missing attribute + should not be treated as a failure. + (Contributed by Serhiy Storchaka in :gh:`106521`.) + * If Python is built in :ref:`debug mode ` or :option:`with assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and :c:func:`PyList_SET_ITEM` now check the index argument with an assertion. diff --git a/Include/abstract.h b/Include/abstract.h index c84d2c704e9605..f47ea1ae3210ea 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -60,6 +60,38 @@ extern "C" { This is the equivalent of the Python expression: o.attr_name. */ +/* Implemented elsewhere: + + int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result); + + Variant of PyObject_GetAttr() which doesn't raise AttributeError + if the attribute is not found. + + If the attribute is found, return 1 and set *result to a new strong + reference to the attribute. + If the attribute is not found, return 0 and set *result to NULL; + the AttributeError is silenced. + If an error other than AttributeError is raised, return -1 and + set *result to NULL. +*/ + + +/* Implemented elsewhere: + + int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result); + + Variant of PyObject_GetAttrString() which doesn't raise AttributeError + if the attribute is not found. + + If the attribute is found, return 1 and set *result to a new strong + reference to the attribute. + If the attribute is not found, return 0 and set *result to NULL; + the AttributeError is silenced. + If an error other than AttributeError is raised, return -1 and + set *result to NULL. +*/ + + /* Implemented elsewhere: int PyObject_SetAttrString(PyObject *o, const char *attr_name, PyObject *v); diff --git a/Include/cpython/object.h b/Include/cpython/object.h index ef9006431bee2f..ba30c567c40ebd 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -294,17 +294,7 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *); PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, _Py_Identifier *); PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, _Py_Identifier *, PyObject *); -/* Replacements of PyObject_GetAttr() and _PyObject_GetAttrId() which - don't raise AttributeError. - - Return 1 and set *result != NULL if an attribute is found. - Return 0 and set *result == NULL if an attribute is not found; - an AttributeError is silenced. - Return -1 and set *result == NULL if an error other than AttributeError - is raised. -*/ -PyAPI_FUNC(int) _PyObject_LookupAttr(PyObject *, PyObject *, PyObject **); -PyAPI_FUNC(int) _PyObject_LookupAttrId(PyObject *, _Py_Identifier *, PyObject **); +#define _PyObject_LookupAttr PyObject_GetOptionalAttr PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); diff --git a/Include/object.h b/Include/object.h index dccab07e5f2c6f..7f2e4e90615e7b 100644 --- a/Include/object.h +++ b/Include/object.h @@ -394,6 +394,10 @@ PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); PyAPI_FUNC(int) PyObject_DelAttrString(PyObject *v, const char *name); PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 +PyAPI_FUNC(int) PyObject_GetOptionalAttr(PyObject *, PyObject *, PyObject **); +PyAPI_FUNC(int) PyObject_GetOptionalAttrString(PyObject *, const char *, PyObject **); +#endif PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); PyAPI_FUNC(int) PyObject_DelAttr(PyObject *v, PyObject *name); PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 20bc2624c81361..6aa3cf382f9c63 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -531,6 +531,8 @@ def test_windows_feature_macros(self): "PyObject_GetBuffer", "PyObject_GetItem", "PyObject_GetIter", + "PyObject_GetOptionalAttr", + "PyObject_GetOptionalAttrString", "PyObject_GetTypeData", "PyObject_HasAttr", "PyObject_HasAttrString", diff --git a/Misc/NEWS.d/next/C API/2023-07-07-19-14-00.gh-issue-106521.Veh9f3.rst b/Misc/NEWS.d/next/C API/2023-07-07-19-14-00.gh-issue-106521.Veh9f3.rst new file mode 100644 index 00000000000000..f38fd271e8a440 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-07-19-14-00.gh-issue-106521.Veh9f3.rst @@ -0,0 +1 @@ +Add :c:func:`PyObject_GetOptionalAttr` and :c:func:`PyObject_GetOptionalAttrString` functions. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index c61fedf8390e28..1f6519cb1e1b26 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2436,3 +2436,7 @@ added = '3.13' [function.PyObject_DelAttrString] added = '3.13' +[function.PyObject_GetOptionalAttr] + added = '3.13' +[function.PyObject_GetOptionalAttrString] + added = '3.13' diff --git a/Objects/object.c b/Objects/object.c index 540ba5d07427cd..d30e048335ab63 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -692,7 +692,7 @@ _PyObject_FunctionStr(PyObject *x) { assert(!PyErr_Occurred()); PyObject *qualname; - int ret = _PyObject_LookupAttr(x, &_Py_ID(__qualname__), &qualname); + int ret = PyObject_GetOptionalAttr(x, &_Py_ID(__qualname__), &qualname); if (qualname == NULL) { if (ret < 0) { return NULL; @@ -701,7 +701,7 @@ _PyObject_FunctionStr(PyObject *x) } PyObject *module; PyObject *result = NULL; - ret = _PyObject_LookupAttr(x, &_Py_ID(__module__), &module); + ret = PyObject_GetOptionalAttr(x, &_Py_ID(__module__), &module); if (module != NULL && module != Py_None) { ret = PyObject_RichCompareBool(module, &_Py_ID(builtins), Py_NE); if (ret < 0) { @@ -957,7 +957,7 @@ _PyObject_IsAbstract(PyObject *obj) if (obj == NULL) return 0; - res = _PyObject_LookupAttr(obj, &_Py_ID(__isabstractmethod__), &isabstract); + res = PyObject_GetOptionalAttr(obj, &_Py_ID(__isabstractmethod__), &isabstract); if (res > 0) { res = PyObject_IsTrue(isabstract); Py_DECREF(isabstract); @@ -1049,7 +1049,7 @@ PyObject_GetAttr(PyObject *v, PyObject *name) } int -_PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) +PyObject_GetOptionalAttr(PyObject *v, PyObject *name, PyObject **result) { PyTypeObject *tp = Py_TYPE(v); @@ -1117,21 +1117,35 @@ _PyObject_LookupAttr(PyObject *v, PyObject *name, PyObject **result) } int -_PyObject_LookupAttrId(PyObject *v, _Py_Identifier *name, PyObject **result) +PyObject_GetOptionalAttrString(PyObject *obj, const char *name, PyObject **result) { - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) { - *result = NULL; + if (Py_TYPE(obj)->tp_getattr == NULL) { + PyObject *oname = PyUnicode_FromString(name); + if (oname == NULL) { + *result = NULL; + return -1; + } + int rc = PyObject_GetOptionalAttr(obj, oname, result); + Py_DECREF(oname); + return rc; + } + + *result = (*Py_TYPE(obj)->tp_getattr)(obj, (char*)name); + if (*result != NULL) { + return 1; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { return -1; } - return _PyObject_LookupAttr(v, oname, result); + PyErr_Clear(); + return 0; } int PyObject_HasAttr(PyObject *v, PyObject *name) { PyObject *res; - if (_PyObject_LookupAttr(v, name, &res) < 0) { + if (PyObject_GetOptionalAttr(v, name, &res) < 0) { PyErr_Clear(); return 0; } diff --git a/PC/python3dll.c b/PC/python3dll.c index a7173911c7c1e8..7d7192958eeb98 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -469,6 +469,8 @@ EXPORT_FUNC(PyObject_GetAttrString) EXPORT_FUNC(PyObject_GetBuffer) EXPORT_FUNC(PyObject_GetItem) EXPORT_FUNC(PyObject_GetIter) +EXPORT_FUNC(PyObject_GetOptionalAttr) +EXPORT_FUNC(PyObject_GetOptionalAttrString) EXPORT_FUNC(PyObject_GetTypeData) EXPORT_FUNC(PyObject_HasAttr) EXPORT_FUNC(PyObject_HasAttrString) From b444bfb0a325dea8c29f7b1828233b00fbf4a1cb Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Tue, 11 Jul 2023 20:35:41 +0100 Subject: [PATCH 355/446] gh-106597: Add debugging struct with offsets for out-of-process tools (#106598) --- Include/internal/pycore_runtime.h | 89 +++++++++++++++++++ Include/internal/pycore_runtime_init.h | 58 +++++++++++- ...-07-10-15-30-45.gh-issue-106597.WAZ14y.rst | 5 ++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 5ed97e9715b2b0..a16d4202b616db 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -53,12 +53,101 @@ typedef struct _Py_AuditHookEntry { void *userData; } _Py_AuditHookEntry; +typedef struct _Py_DebugOffsets { + char cookie[8]; + uint64_t version; + // Runtime state offset; + struct _runtime_state { + off_t finalizing; + off_t interpreters_head; + } runtime_state; + + // Interpreter state offset; + struct _interpreter_state { + off_t next; + off_t threads_head; + off_t gc; + off_t imports_modules; + off_t sysdict; + off_t builtins; + off_t ceval_gil; + off_t gil_runtime_state_locked; + off_t gil_runtime_state_holder; + } interpreter_state; + + // Thread state offset; + struct _thread_state{ + off_t prev; + off_t next; + off_t interp; + off_t cframe; + off_t thread_id; + off_t native_thread_id; + } thread_state; + + // InterpreterFrame offset; + struct _interpreter_frame { + off_t previous; + off_t executable; + off_t prev_instr; + off_t localsplus; + off_t owner; + } interpreter_frame; + + // CFrame offset; + struct _cframe { + off_t current_frame; + off_t previous; + } cframe; + + // Code object offset; + struct _code_object { + off_t filename; + off_t name; + off_t linetable; + off_t firstlineno; + off_t argcount; + off_t localsplusnames; + off_t localspluskinds; + off_t co_code_adaptive; + } code_object; + + // PyObject offset; + struct _pyobject { + off_t ob_type; + } pyobject; + + // PyTypeObject object offset; + struct _type_object { + off_t tp_name; + } type_object; + + // PyTuple object offset; + struct _tuple_object { + off_t ob_item; + } tuple_object; +} _Py_DebugOffsets; + /* Full Python runtime state */ /* _PyRuntimeState holds the global state for the CPython runtime. That data is exposed in the internal API as a static variable (_PyRuntime). */ typedef struct pyruntimestate { + /* This field must be first to facilitate locating it by out of process + * debuggers. Out of process debuggers will use the offsets contained in this + * field to be able to locate other fields in several interpreter structures + * in a way that doesn't require them to know the exact layout of those + * structures. + * + * IMPORTANT: + * This struct is **NOT** backwards compatible between minor version of the + * interpreter and the members, order of members and size can change between + * minor versions. This struct is only guaranteed to be stable between patch + * versions for a given minor version of the interpreter. + */ + _Py_DebugOffsets debug_offsets; + /* Has been initialized to a safe state. In order to be effective, this must be set to 0 during or right diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index b507de0437d9aa..e72e7422c7207e 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -21,9 +21,65 @@ extern PyTypeObject _PyExc_MemoryError; /* The static initializers defined here should only be used in the runtime init code (in pystate.c and pylifecycle.c). */ - #define _PyRuntimeState_INIT(runtime) \ { \ + .debug_offsets = { \ + .cookie = "xdebugpy", \ + .version = PY_VERSION_HEX, \ + .runtime_state = { \ + .finalizing = offsetof(_PyRuntimeState, _finalizing), \ + .interpreters_head = offsetof(_PyRuntimeState, interpreters.head), \ + }, \ + .interpreter_state = { \ + .next = offsetof(PyInterpreterState, next), \ + .threads_head = offsetof(PyInterpreterState, threads.head), \ + .gc = offsetof(PyInterpreterState, gc), \ + .imports_modules = offsetof(PyInterpreterState, imports.modules), \ + .sysdict = offsetof(PyInterpreterState, sysdict), \ + .builtins = offsetof(PyInterpreterState, builtins), \ + .ceval_gil = offsetof(PyInterpreterState, ceval.gil), \ + .gil_runtime_state_locked = offsetof(PyInterpreterState, _gil.locked), \ + .gil_runtime_state_holder = offsetof(PyInterpreterState, _gil.last_holder), \ + }, \ + .thread_state = { \ + .prev = offsetof(PyThreadState, prev), \ + .next = offsetof(PyThreadState, next), \ + .interp = offsetof(PyThreadState, interp), \ + .cframe = offsetof(PyThreadState, cframe), \ + .thread_id = offsetof(PyThreadState, thread_id), \ + .native_thread_id = offsetof(PyThreadState, native_thread_id), \ + }, \ + .interpreter_frame = { \ + .previous = offsetof(_PyInterpreterFrame, previous), \ + .executable = offsetof(_PyInterpreterFrame, f_executable), \ + .prev_instr = offsetof(_PyInterpreterFrame, prev_instr), \ + .localsplus = offsetof(_PyInterpreterFrame, localsplus), \ + .owner = offsetof(_PyInterpreterFrame, owner), \ + }, \ + .cframe = { \ + .current_frame = offsetof(_PyCFrame, current_frame), \ + .previous = offsetof(_PyCFrame, previous), \ + }, \ + .code_object = { \ + .filename = offsetof(PyCodeObject, co_filename), \ + .name = offsetof(PyCodeObject, co_name), \ + .linetable = offsetof(PyCodeObject, co_linetable), \ + .firstlineno = offsetof(PyCodeObject, co_firstlineno), \ + .argcount = offsetof(PyCodeObject, co_argcount), \ + .localsplusnames = offsetof(PyCodeObject, co_localsplusnames), \ + .localspluskinds = offsetof(PyCodeObject, co_localspluskinds), \ + .co_code_adaptive = offsetof(PyCodeObject, co_code_adaptive), \ + }, \ + .pyobject = { \ + .ob_type = offsetof(PyObject, ob_type), \ + }, \ + .type_object = { \ + .tp_name = offsetof(PyTypeObject, tp_name), \ + }, \ + .tuple_object = { \ + .ob_item = offsetof(PyTupleObject, ob_item), \ + }, \ + }, \ .allocators = { \ .standard = _pymem_allocators_standard_INIT(runtime), \ .debug = _pymem_allocators_debug_INIT, \ diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst new file mode 100644 index 00000000000000..bbe455d652f50e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-10-15-30-45.gh-issue-106597.WAZ14y.rst @@ -0,0 +1,5 @@ +A new debug structure of offsets has been added to the ``_PyRuntimeState`` +that will help out-of-process debuggers and profilers to obtain the offsets +to relevant interpreter structures in a way that is agnostic of how Python +was compiled and that doesn't require copying the headers. Patch by Pablo +Galindo From 4bf43710d1e1f19cc46b116b5d8524f6c75dabfa Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 11 Jul 2023 23:04:12 +0300 Subject: [PATCH 356/446] gh-106307: C API: Add PyMapping_GetOptionalItem() function (GH-106308) Also add PyMapping_GetOptionalItemString() function. --- Doc/c-api/mapping.rst | 30 + Doc/data/stable_abi.dat | 2 + Doc/whatsnew/3.13.rst | 8 + Include/abstract.h | 15 + Lib/test/test_stable_abi_ctypes.py | 2 + ...-07-08-12-24-17.gh-issue-106307.FVnkBw.rst | 1 + Misc/stable_abi.toml | 4 + Modules/_lzmamodule.c | 22 +- Modules/_pickle.c | 15 +- Objects/abstract.c | 40 + PC/python3dll.c | 2 + Python/bytecodes.c | 116 +-- Python/executor_cases.c.h | 482 +++++----- Python/generated_cases.c.h | 872 ++++++++---------- Python/import.c | 24 +- 15 files changed, 739 insertions(+), 896 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-07-08-12-24-17.gh-issue-106307.FVnkBw.rst diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst index cffb0ed50fb77d..9176a4652cbf29 100644 --- a/Doc/c-api/mapping.rst +++ b/Doc/c-api/mapping.rst @@ -33,6 +33,36 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and See also :c:func:`PyObject_GetItem`. +.. c:function:: int PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) + + Variant of :c:func:`PyObject_GetItem` which doesn't raise + :exc:`KeyError` if the key is not found. + + If the key is found, return ``1`` and set *\*result* to a new + :term:`strong reference` to the corresponding value. + If the key is not found, return ``0`` and set *\*result* to ``NULL``; + the :exc:`KeyError` is silenced. + If an error other than :exc:`KeyError` is raised, return ``-1`` and + set *\*result* to ``NULL``. + + .. versionadded:: 3.13 + + +.. c:function:: int PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result) + + Variant of :c:func:`PyMapping_GetItemString` which doesn't raise + :exc:`KeyError` if the key is not found. + + If the key is found, return ``1`` and set *\*result* to a new + :term:`strong reference` to the corresponding value. + If the key is not found, return ``0`` and set *\*result* to ``NULL``; + the :exc:`KeyError` is silenced. + If an error other than :exc:`KeyError` is raised, return ``-1`` and + set *\*result* to ``NULL``. + + .. versionadded:: 3.13 + + .. c:function:: int PyMapping_SetItemString(PyObject *o, const char *key, PyObject *v) Map the string *key* to the value *v* in object *o*. Returns ``-1`` on diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index d7e8b5b464a71b..e3dd3dab27a035 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -370,6 +370,8 @@ var,PyLong_Type,3.2,, var,PyMap_Type,3.2,, function,PyMapping_Check,3.2,, function,PyMapping_GetItemString,3.2,, +function,PyMapping_GetOptionalItem,3.13,, +function,PyMapping_GetOptionalItemString,3.13,, function,PyMapping_HasKey,3.2,, function,PyMapping_HasKeyString,3.2,, function,PyMapping_Items,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 62981673140cf7..dc020682ac1edd 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -742,6 +742,14 @@ New Features should not be treated as a failure. (Contributed by Serhiy Storchaka in :gh:`106521`.) +* Add :c:func:`PyMapping_GetOptionalItem` and + :c:func:`PyMapping_GetOptionalItemString`: variants of + :c:func:`PyObject_GetItem` and :c:func:`PyMapping_GetItemString` which don't + raise :exc:`KeyError` if the key is not found. + These variants are more convenient and faster if the missing key should not + be treated as a failure. + (Contributed by Serhiy Storchaka in :gh:`106307`.) + * If Python is built in :ref:`debug mode ` or :option:`with assertions <--with-assertions>`, :c:func:`PyTuple_SET_ITEM` and :c:func:`PyList_SET_ITEM` now check the index argument with an assertion. diff --git a/Include/abstract.h b/Include/abstract.h index f47ea1ae3210ea..dd915004e7834e 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -840,6 +840,21 @@ PyAPI_FUNC(PyObject *) PyMapping_Items(PyObject *o); PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, const char *key); +/* Variants of PyObject_GetItem() and PyMapping_GetItemString() which don't + raise KeyError if the key is not found. + + If the key is found, return 1 and set *result to a new strong + reference to the corresponding value. + If the key is not found, return 0 and set *result to NULL; + the KeyError is silenced. + If an error other than KeyError is raised, return -1 and + set *result to NULL. +*/ +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 +PyAPI_FUNC(int) PyMapping_GetOptionalItem(PyObject *, PyObject *, PyObject **); +PyAPI_FUNC(int) PyMapping_GetOptionalItemString(PyObject *, const char *, PyObject **); +#endif + /* Map the string 'key' to the value 'v' in the mapping 'o'. Returns -1 on failure. diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 6aa3cf382f9c63..e92e986b293377 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -398,6 +398,8 @@ def test_windows_feature_macros(self): "PyMap_Type", "PyMapping_Check", "PyMapping_GetItemString", + "PyMapping_GetOptionalItem", + "PyMapping_GetOptionalItemString", "PyMapping_HasKey", "PyMapping_HasKeyString", "PyMapping_Items", diff --git a/Misc/NEWS.d/next/C API/2023-07-08-12-24-17.gh-issue-106307.FVnkBw.rst b/Misc/NEWS.d/next/C API/2023-07-08-12-24-17.gh-issue-106307.FVnkBw.rst new file mode 100644 index 00000000000000..dc1ab8d3e3fb83 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-07-08-12-24-17.gh-issue-106307.FVnkBw.rst @@ -0,0 +1 @@ +Add :c:func:`PyMapping_GetOptionalItem` function. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 1f6519cb1e1b26..8ea8fde68b833a 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2440,3 +2440,7 @@ added = '3.13' [function.PyObject_GetOptionalAttrString] added = '3.13' +[function.PyMapping_GetOptionalItem] + added = '3.13' +[function.PyMapping_GetOptionalItemString] + added = '3.13' diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index ba0987ee0abca1..02a32ddccb3ed7 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -240,15 +240,10 @@ parse_filter_spec_lzma(_lzma_state *state, PyObject *spec) /* First, fill in default values for all the options using a preset. Then, override the defaults with any values given by the caller. */ - preset_obj = PyMapping_GetItemString(spec, "preset"); - if (preset_obj == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - } - else { - return NULL; - } - } else { + if (PyMapping_GetOptionalItemString(spec, "preset", &preset_obj) < 0) { + return NULL; + } + if (preset_obj != NULL) { int ok = uint32_converter(preset_obj, &preset); Py_DECREF(preset_obj); if (!ok) { @@ -345,11 +340,12 @@ lzma_filter_converter(_lzma_state *state, PyObject *spec, void *ptr) "Filter specifier must be a dict or dict-like object"); return 0; } - id_obj = PyMapping_GetItemString(spec, "id"); + if (PyMapping_GetOptionalItemString(spec, "id", &id_obj) < 0) { + return 0; + } if (id_obj == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_SetString(PyExc_ValueError, - "Filter specifier must have an \"id\" entry"); + PyErr_SetString(PyExc_ValueError, + "Filter specifier must have an \"id\" entry"); return 0; } f->id = PyLong_AsUnsignedLongLong(id_obj); diff --git a/Modules/_pickle.c b/Modules/_pickle.c index a68a0aaa64c2b5..5ecf7ca7cb9bc5 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4438,16 +4438,13 @@ save(PickleState *st, PicklerObject *self, PyObject *obj, int pers_save) PyObject_GetItem and _PyObject_GetAttrId used below. */ Py_INCREF(reduce_func); } - } else { - reduce_func = PyObject_GetItem(self->dispatch_table, - (PyObject *)type); - if (reduce_func == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) - PyErr_Clear(); - else - goto error; - } } + else if (PyMapping_GetOptionalItem(self->dispatch_table, (PyObject *)type, + &reduce_func) < 0) + { + goto error; + } + if (reduce_func != NULL) { reduce_value = _Pickle_FastCall(reduce_func, Py_NewRef(obj)); } diff --git a/Objects/abstract.c b/Objects/abstract.c index 80a40944d6d219..e595bc91c220f6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -199,6 +199,30 @@ PyObject_GetItem(PyObject *o, PyObject *key) return type_error("'%.200s' object is not subscriptable", o); } +int +PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) +{ + if (PyDict_CheckExact(obj)) { + *result = PyDict_GetItemWithError(obj, key); /* borrowed */ + if (*result) { + Py_INCREF(*result); + return 1; + } + return PyErr_Occurred() ? -1 : 0; + } + + *result = PyObject_GetItem(obj, key); + if (*result) { + return 1; + } + assert(PyErr_Occurred()); + if (!PyErr_ExceptionMatches(PyExc_KeyError)) { + return -1; + } + PyErr_Clear(); + return 0; +} + int PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) { @@ -2366,6 +2390,22 @@ PyMapping_GetItemString(PyObject *o, const char *key) return r; } +int +PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result) +{ + if (key == NULL) { + null_error(); + return -1; + } + PyObject *okey = PyUnicode_FromString(key); + if (okey == NULL) { + return -1; + } + int rc = PyMapping_GetOptionalItem(obj, okey, result); + Py_DECREF(okey); + return rc; +} + int PyMapping_SetItemString(PyObject *o, const char *key, PyObject *value) { diff --git a/PC/python3dll.c b/PC/python3dll.c index 7d7192958eeb98..8f2df6950cfc05 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -352,6 +352,8 @@ EXPORT_FUNC(PyLong_FromVoidPtr) EXPORT_FUNC(PyLong_GetInfo) EXPORT_FUNC(PyMapping_Check) EXPORT_FUNC(PyMapping_GetItemString) +EXPORT_FUNC(PyMapping_GetOptionalItem) +EXPORT_FUNC(PyMapping_GetOptionalItemString) EXPORT_FUNC(PyMapping_HasKey) EXPORT_FUNC(PyMapping_HasKeyString) EXPORT_FUNC(PyMapping_Items) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3ba0d0f7e292f9..2f6b8c5ae2f9cb 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1086,26 +1086,11 @@ dummy_func( } inst(LOAD_BUILD_CLASS, ( -- bc)) { - if (PyDict_CheckExact(BUILTINS())) { - bc = _PyDict_GetItemWithError(BUILTINS(), - &_Py_ID(__build_class__)); - if (bc == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - } - ERROR_IF(true, error); - } - Py_INCREF(bc); - } - else { - bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); - if (bc == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - ERROR_IF(true, error); - } + ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc) < 0, error); + if (bc == NULL) { + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + ERROR_IF(true, error); } } @@ -1280,25 +1265,9 @@ dummy_func( op(_LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - } - else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { + Py_DECREF(mod_or_class_dict); + goto error; } Py_DECREF(mod_or_class_dict); if (v == NULL) { @@ -1310,28 +1279,14 @@ dummy_func( goto error; } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) { + goto error; } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } + if (v == NULL) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + goto error; } } } @@ -1381,19 +1336,14 @@ dummy_func( /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - v = PyObject_GetItem(GLOBALS(), name); + ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0, error); if (v == NULL) { - ERROR_IF(!_PyErr_ExceptionMatches(tstate, PyExc_KeyError), error); - _PyErr_Clear(tstate); - /* namespace 2: builtins */ - v = PyObject_GetItem(BUILTINS(), name); + ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0, error); if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); ERROR_IF(true, error); } } @@ -1466,25 +1416,9 @@ dummy_func( assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); - if (PyDict_CheckExact(class_dict)) { - value = PyDict_GetItemWithError(class_dict, name); - if (value != NULL) { - Py_INCREF(value); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(class_dict); - goto error; - } - } - else { - value = PyObject_GetItem(class_dict, name); - if (value == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(class_dict, name, &value) < 0) { + Py_DECREF(class_dict); + goto error; } Py_DECREF(class_dict); if (!value) { @@ -1622,10 +1556,8 @@ dummy_func( } else { /* do the same if locals() is not a dict */ - ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); + ERROR_IF(PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0, error); if (ann_dict == NULL) { - ERROR_IF(!_PyErr_ExceptionMatches(tstate, PyExc_KeyError), error); - _PyErr_Clear(tstate); ann_dict = PyDict_New(); ERROR_IF(ann_dict == NULL, error); err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ba854be7f6c05e..681efb97d89a5f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -844,28 +844,13 @@ case LOAD_BUILD_CLASS: { PyObject *bc; #line 1089 "Python/bytecodes.c" - if (PyDict_CheckExact(BUILTINS())) { - bc = _PyDict_GetItemWithError(BUILTINS(), - &_Py_ID(__build_class__)); - if (bc == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - } - if (true) goto error; - } - Py_INCREF(bc); - } - else { - bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); - if (bc == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - if (true) goto error; - } + if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc) < 0) goto error; + if (bc == NULL) { + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + if (true) goto error; } - #line 869 "Python/executor_cases.c.h" + #line 854 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -873,33 +858,33 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; - #line 1114 "Python/bytecodes.c" + #line 1099 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 884 "Python/executor_cases.c.h" + #line 869 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1121 "Python/bytecodes.c" + #line 1106 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 893 "Python/executor_cases.c.h" + #line 878 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1128 "Python/bytecodes.c" + #line 1113 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 897 "Python/executor_cases.c.h" + #line 882 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_NAME: { - #line 1132 "Python/bytecodes.c" + #line 1117 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -916,14 +901,14 @@ name); goto error; } - #line 920 "Python/executor_cases.c.h" + #line 905 "Python/executor_cases.c.h" break; } case UNPACK_SEQUENCE: { static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1158 "Python/bytecodes.c" + #line 1143 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -936,11 +921,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 940 "Python/executor_cases.c.h" + #line 925 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1171 "Python/bytecodes.c" + #line 1156 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 944 "Python/executor_cases.c.h" + #line 929 "Python/executor_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); break; @@ -949,14 +934,14 @@ case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1175 "Python/bytecodes.c" + #line 1160 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 960 "Python/executor_cases.c.h" + #line 945 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -966,7 +951,7 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1185 "Python/bytecodes.c" + #line 1170 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -974,7 +959,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 978 "Python/executor_cases.c.h" + #line 963 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -984,7 +969,7 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1196 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -992,7 +977,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 996 "Python/executor_cases.c.h" + #line 981 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1001,49 +986,49 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; - #line 1207 "Python/bytecodes.c" + #line 1192 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1009 "Python/executor_cases.c.h" + #line 994 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1211 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1013 "Python/executor_cases.c.h" + #line 998 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; - #line 1242 "Python/bytecodes.c" + #line 1227 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_DelAttr(owner, name); - #line 1023 "Python/executor_cases.c.h" + #line 1008 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1245 "Python/bytecodes.c" + #line 1230 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1027 "Python/executor_cases.c.h" + #line 1012 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; - #line 1249 "Python/bytecodes.c" + #line 1234 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1037 "Python/executor_cases.c.h" + #line 1022 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1252 "Python/bytecodes.c" + #line 1237 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1041 "Python/executor_cases.c.h" + #line 1026 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_GLOBAL: { - #line 1256 "Python/bytecodes.c" + #line 1241 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1055,13 +1040,13 @@ } goto error; } - #line 1059 "Python/executor_cases.c.h" + #line 1044 "Python/executor_cases.c.h" break; } case _LOAD_LOCALS: { PyObject *locals; - #line 1270 "Python/bytecodes.c" + #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1069,7 +1054,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1073 "Python/executor_cases.c.h" + #line 1058 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -1078,27 +1063,11 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; - #line 1282 "Python/bytecodes.c" + #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - } - else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { + Py_DECREF(mod_or_class_dict); + goto error; } Py_DECREF(mod_or_class_dict); if (v == NULL) { @@ -1110,32 +1079,18 @@ goto error; } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) { + goto error; } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } + if (v == NULL) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + goto error; } } } - #line 1139 "Python/executor_cases.c.h" + #line 1094 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } @@ -1144,7 +1099,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1351 "Python/bytecodes.c" + #line 1306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1178,25 +1133,20 @@ /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - v = PyObject_GetItem(GLOBALS(), name); + if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error; if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; - _PyErr_Clear(tstate); - /* namespace 2: builtins */ - v = PyObject_GetItem(BUILTINS(), name); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error; if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); if (true) goto error; } } } null = NULL; - #line 1200 "Python/executor_cases.c.h" + #line 1150 "Python/executor_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1205,16 +1155,16 @@ } case DELETE_FAST: { - #line 1435 "Python/bytecodes.c" + #line 1385 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1213 "Python/executor_cases.c.h" + #line 1163 "Python/executor_cases.c.h" break; } case DELETE_DEREF: { - #line 1452 "Python/bytecodes.c" + #line 1402 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1225,37 +1175,21 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1229 "Python/executor_cases.c.h" + #line 1179 "Python/executor_cases.c.h" break; } case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1465 "Python/bytecodes.c" + #line 1415 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); - if (PyDict_CheckExact(class_dict)) { - value = PyDict_GetItemWithError(class_dict, name); - if (value != NULL) { - Py_INCREF(value); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(class_dict); - goto error; - } - } - else { - value = PyObject_GetItem(class_dict, name); - if (value == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(class_dict, name, &value) < 0) { + Py_DECREF(class_dict); + goto error; } Py_DECREF(class_dict); if (!value) { @@ -1267,14 +1201,14 @@ } Py_INCREF(value); } - #line 1271 "Python/executor_cases.c.h" + #line 1205 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } case LOAD_DEREF: { PyObject *value; - #line 1502 "Python/bytecodes.c" + #line 1436 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1282,7 +1216,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1286 "Python/executor_cases.c.h" + #line 1220 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1290,18 +1224,18 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1512 "Python/bytecodes.c" + #line 1446 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1299 "Python/executor_cases.c.h" + #line 1233 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case COPY_FREE_VARS: { - #line 1519 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1312,22 +1246,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1316 "Python/executor_cases.c.h" + #line 1250 "Python/executor_cases.c.h" break; } case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1532 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1325 "Python/executor_cases.c.h" + #line 1259 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1534 "Python/bytecodes.c" + #line 1468 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1331 "Python/executor_cases.c.h" + #line 1265 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1337,10 +1271,10 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1538 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1344 "Python/executor_cases.c.h" + #line 1278 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1350,10 +1284,10 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1543 "Python/bytecodes.c" + #line 1477 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1357 "Python/executor_cases.c.h" + #line 1291 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1363,7 +1297,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1548 "Python/bytecodes.c" + #line 1482 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1374,13 +1308,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1378 "Python/executor_cases.c.h" + #line 1312 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1559 "Python/bytecodes.c" + #line 1493 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1384 "Python/executor_cases.c.h" + #line 1318 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1389,13 +1323,13 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1566 "Python/bytecodes.c" + #line 1500 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1395 "Python/executor_cases.c.h" + #line 1329 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1568 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1399 "Python/executor_cases.c.h" + #line 1333 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1403,7 +1337,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1572 "Python/bytecodes.c" + #line 1506 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1418,7 +1352,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1422 "Python/executor_cases.c.h" + #line 1356 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1428,7 +1362,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1589 "Python/bytecodes.c" + #line 1523 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1436,13 +1370,13 @@ if (map == NULL) goto error; - #line 1440 "Python/executor_cases.c.h" + #line 1374 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1597 "Python/bytecodes.c" + #line 1531 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1446 "Python/executor_cases.c.h" + #line 1380 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1450,7 +1384,7 @@ } case SETUP_ANNOTATIONS: { - #line 1601 "Python/bytecodes.c" + #line 1535 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1475,10 +1409,8 @@ } else { /* do the same if locals() is not a dict */ - ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); + if (PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0) goto error; if (ann_dict == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; - _PyErr_Clear(tstate); ann_dict = PyDict_New(); if (ann_dict == NULL) goto error; err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), @@ -1490,7 +1422,7 @@ Py_DECREF(ann_dict); } } - #line 1494 "Python/executor_cases.c.h" + #line 1426 "Python/executor_cases.c.h" break; } @@ -1498,7 +1430,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1643 "Python/bytecodes.c" + #line 1575 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1508,14 +1440,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1512 "Python/executor_cases.c.h" + #line 1444 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1653 "Python/bytecodes.c" + #line 1585 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1519 "Python/executor_cases.c.h" + #line 1451 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1523,7 +1455,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1657 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1531,12 +1463,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1535 "Python/executor_cases.c.h" + #line 1467 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1665 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1540 "Python/executor_cases.c.h" + #line 1472 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1544,17 +1476,17 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1671 "Python/bytecodes.c" + #line 1603 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1553 "Python/executor_cases.c.h" + #line 1485 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1676 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1558 "Python/executor_cases.c.h" + #line 1490 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1563,13 +1495,13 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1682 "Python/bytecodes.c" + #line 1614 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1573 "Python/executor_cases.c.h" + #line 1505 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1580,20 +1512,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1765 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1591 "Python/executor_cases.c.h" + #line 1523 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1772 "Python/bytecodes.c" + #line 1704 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1597 "Python/executor_cases.c.h" + #line 1529 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1607,7 +1539,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1776 "Python/bytecodes.c" + #line 1708 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1630,7 +1562,7 @@ res = res2; res2 = NULL; } - #line 1634 "Python/executor_cases.c.h" + #line 1566 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1642,7 +1574,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1817 "Python/bytecodes.c" + #line 1749 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1676,9 +1608,9 @@ NULL | meth | arg1 | ... | argN */ - #line 1680 "Python/executor_cases.c.h" + #line 1612 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1851 "Python/bytecodes.c" + #line 1783 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1687,12 +1619,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 1691 "Python/executor_cases.c.h" + #line 1623 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1860 "Python/bytecodes.c" + #line 1792 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 1696 "Python/executor_cases.c.h" + #line 1628 "Python/executor_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -1704,7 +1636,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2093 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1717,10 +1649,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 1721 "Python/executor_cases.c.h" + #line 1653 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2106 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -1728,7 +1660,7 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 1732 "Python/executor_cases.c.h" + #line 1664 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1738,7 +1670,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2116 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1750,7 +1682,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1754 "Python/executor_cases.c.h" + #line 1686 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1760,7 +1692,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2131 "Python/bytecodes.c" + #line 2063 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1776,7 +1708,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1780 "Python/executor_cases.c.h" + #line 1712 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1786,7 +1718,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2150 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1799,7 +1731,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1803 "Python/executor_cases.c.h" + #line 1735 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1809,14 +1741,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2165 "Python/bytecodes.c" + #line 2097 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1815 "Python/executor_cases.c.h" + #line 1747 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2167 "Python/bytecodes.c" + #line 2099 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1820 "Python/executor_cases.c.h" + #line 1752 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1826,15 +1758,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2171 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1832 "Python/executor_cases.c.h" + #line 1764 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2173 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1838 "Python/executor_cases.c.h" + #line 1770 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1845,12 +1777,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2178 "Python/bytecodes.c" + #line 2110 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1851 "Python/executor_cases.c.h" + #line 1783 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2180 "Python/bytecodes.c" + #line 2112 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1858,10 +1790,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1862 "Python/executor_cases.c.h" + #line 1794 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2188 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1870,7 +1802,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1874 "Python/executor_cases.c.h" + #line 1806 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1880,21 +1812,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2199 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1887 "Python/executor_cases.c.h" + #line 1819 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2202 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1894 "Python/executor_cases.c.h" + #line 1826 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2207 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1898 "Python/executor_cases.c.h" + #line 1830 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1902,17 +1834,17 @@ case IS_NONE: { PyObject *value = stack_pointer[-1]; PyObject *b; - #line 2286 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 1912 "Python/executor_cases.c.h" + #line 1844 "Python/executor_cases.c.h" Py_DECREF(value); - #line 2292 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" } - #line 1916 "Python/executor_cases.c.h" + #line 1848 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1920,13 +1852,13 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2309 "Python/bytecodes.c" + #line 2241 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1930 "Python/executor_cases.c.h" + #line 1862 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1937,16 +1869,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2317 "Python/bytecodes.c" + #line 2249 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1946 "Python/executor_cases.c.h" + #line 1878 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2322 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1954,7 +1886,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1958 "Python/executor_cases.c.h" + #line 1890 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1963,10 +1895,10 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2264 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1970 "Python/executor_cases.c.h" + #line 1902 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1975,10 +1907,10 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2337 "Python/bytecodes.c" + #line 2269 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1982 "Python/executor_cases.c.h" + #line 1914 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1988,11 +1920,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2342 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1996 "Python/executor_cases.c.h" + #line 1928 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -2001,14 +1933,14 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2348 "Python/bytecodes.c" + #line 2280 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2008 "Python/executor_cases.c.h" + #line 1940 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2351 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2012 "Python/executor_cases.c.h" + #line 1944 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -2016,7 +1948,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2355 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2039,11 +1971,11 @@ if (iter == NULL) { goto error; } - #line 2043 "Python/executor_cases.c.h" + #line 1975 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2378 "Python/bytecodes.c" + #line 2310 "Python/bytecodes.c" } - #line 2047 "Python/executor_cases.c.h" + #line 1979 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -2053,7 +1985,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2610 "Python/bytecodes.c" + #line 2542 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2074,7 +2006,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 2078 "Python/executor_cases.c.h" + #line 2010 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -2083,7 +2015,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2649 "Python/bytecodes.c" + #line 2581 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2093,7 +2025,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 2097 "Python/executor_cases.c.h" + #line 2029 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2102,7 +2034,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3048 "Python/bytecodes.c" + #line 2980 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2110,7 +2042,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 2114 "Python/executor_cases.c.h" + #line 2046 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -2118,7 +2050,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3462 "Python/bytecodes.c" + #line 3394 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2130,7 +2062,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 2134 "Python/executor_cases.c.h" + #line 2066 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -2138,7 +2070,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3476 "Python/bytecodes.c" + #line 3408 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2163,7 +2095,7 @@ default: Py_UNREACHABLE(); } - #line 2167 "Python/executor_cases.c.h" + #line 2099 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -2174,15 +2106,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3526 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 2180 "Python/executor_cases.c.h" + #line 2112 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3528 "Python/bytecodes.c" + #line 3460 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 2186 "Python/executor_cases.c.h" + #line 2118 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -2192,14 +2124,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3532 "Python/bytecodes.c" + #line 3464 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 2203 "Python/executor_cases.c.h" + #line 2135 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -2207,7 +2139,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3541 "Python/bytecodes.c" + #line 3473 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2218,7 +2150,7 @@ else { res = value; } - #line 2222 "Python/executor_cases.c.h" + #line 2154 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -2227,12 +2159,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3554 "Python/bytecodes.c" + #line 3486 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 2236 "Python/executor_cases.c.h" + #line 2168 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2241,10 +2173,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3561 "Python/bytecodes.c" + #line 3493 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 2248 "Python/executor_cases.c.h" + #line 2180 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -2255,7 +2187,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3566 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2270,12 +2202,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 2274 "Python/executor_cases.c.h" + #line 2206 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3581 "Python/bytecodes.c" + #line 3513 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2279 "Python/executor_cases.c.h" + #line 2211 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2284,9 +2216,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3586 "Python/bytecodes.c" + #line 3518 "Python/bytecodes.c" assert(oparg >= 2); - #line 2290 "Python/executor_cases.c.h" + #line 2222 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 325090a60f9d54..eb3de5e5bca97f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1484,28 +1484,13 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; #line 1089 "Python/bytecodes.c" - if (PyDict_CheckExact(BUILTINS())) { - bc = _PyDict_GetItemWithError(BUILTINS(), - &_Py_ID(__build_class__)); - if (bc == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - } - if (true) goto error; - } - Py_INCREF(bc); - } - else { - bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); - if (bc == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - if (true) goto error; - } + if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc) < 0) goto error; + if (bc == NULL) { + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + if (true) goto error; } - #line 1509 "Python/generated_cases.c.h" + #line 1494 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1513,33 +1498,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1114 "Python/bytecodes.c" + #line 1099 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1524 "Python/generated_cases.c.h" + #line 1509 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1121 "Python/bytecodes.c" + #line 1106 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1533 "Python/generated_cases.c.h" + #line 1518 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1128 "Python/bytecodes.c" + #line 1113 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1537 "Python/generated_cases.c.h" + #line 1522 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1132 "Python/bytecodes.c" + #line 1117 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1556,7 +1541,7 @@ name); goto error; } - #line 1560 "Python/generated_cases.c.h" + #line 1545 "Python/generated_cases.c.h" DISPATCH(); } @@ -1564,7 +1549,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1158 "Python/bytecodes.c" + #line 1143 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1577,11 +1562,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1581 "Python/generated_cases.c.h" + #line 1566 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1171 "Python/bytecodes.c" + #line 1156 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1585 "Python/generated_cases.c.h" + #line 1570 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1591,14 +1576,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1175 "Python/bytecodes.c" + #line 1160 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1602 "Python/generated_cases.c.h" + #line 1587 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1609,7 +1594,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1185 "Python/bytecodes.c" + #line 1170 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1617,7 +1602,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1621 "Python/generated_cases.c.h" + #line 1606 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1628,7 +1613,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1196 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1636,7 +1621,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1640 "Python/generated_cases.c.h" + #line 1625 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1646,15 +1631,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1207 "Python/bytecodes.c" + #line 1192 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1654 "Python/generated_cases.c.h" + #line 1639 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1211 "Python/bytecodes.c" + #line 1196 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1658 "Python/generated_cases.c.h" + #line 1643 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1665,7 +1650,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1222 "Python/bytecodes.c" + #line 1207 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1681,12 +1666,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1685 "Python/generated_cases.c.h" + #line 1670 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1238 "Python/bytecodes.c" + #line 1223 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1690 "Python/generated_cases.c.h" + #line 1675 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1694,34 +1679,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1242 "Python/bytecodes.c" + #line 1227 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_DelAttr(owner, name); - #line 1701 "Python/generated_cases.c.h" + #line 1686 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1245 "Python/bytecodes.c" + #line 1230 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1705 "Python/generated_cases.c.h" + #line 1690 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1249 "Python/bytecodes.c" + #line 1234 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1715 "Python/generated_cases.c.h" + #line 1700 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1252 "Python/bytecodes.c" + #line 1237 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1719 "Python/generated_cases.c.h" + #line 1704 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1256 "Python/bytecodes.c" + #line 1241 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1733,7 +1718,7 @@ } goto error; } - #line 1737 "Python/generated_cases.c.h" + #line 1722 "Python/generated_cases.c.h" DISPATCH(); } @@ -1741,7 +1726,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1270 "Python/bytecodes.c" + #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1749,7 +1734,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 1753 "Python/generated_cases.c.h" + #line 1738 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1761,7 +1746,7 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1270 "Python/bytecodes.c" + #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1769,33 +1754,17 @@ if (true) goto error; } Py_INCREF(locals); - #line 1773 "Python/generated_cases.c.h" + #line 1758 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1282 "Python/bytecodes.c" + #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - } - else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { + Py_DECREF(mod_or_class_dict); + goto error; } Py_DECREF(mod_or_class_dict); if (v == NULL) { @@ -1807,32 +1776,18 @@ goto error; } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) { + goto error; } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } + if (v == NULL) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + goto error; } } } - #line 1836 "Python/generated_cases.c.h" + #line 1791 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1845,27 +1800,11 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1282 "Python/bytecodes.c" + #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); - if (PyDict_CheckExact(mod_or_class_dict)) { - v = PyDict_GetItemWithError(mod_or_class_dict, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - } - else { - v = PyObject_GetItem(mod_or_class_dict, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(mod_or_class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { + Py_DECREF(mod_or_class_dict); + goto error; } Py_DECREF(mod_or_class_dict); if (v == NULL) { @@ -1877,32 +1816,18 @@ goto error; } else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) { + goto error; } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } + if (v == NULL) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + goto error; } } } - #line 1906 "Python/generated_cases.c.h" + #line 1831 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1914,7 +1839,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1351 "Python/bytecodes.c" + #line 1306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1948,25 +1873,20 @@ /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - v = PyObject_GetItem(GLOBALS(), name); + if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error; if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; - _PyErr_Clear(tstate); - /* namespace 2: builtins */ - v = PyObject_GetItem(BUILTINS(), name); + if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error; if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); if (true) goto error; } } } null = NULL; - #line 1970 "Python/generated_cases.c.h" + #line 1890 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1980,7 +1900,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1405 "Python/bytecodes.c" + #line 1355 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); @@ -1991,7 +1911,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1995 "Python/generated_cases.c.h" + #line 1915 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2006,7 +1926,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1418 "Python/bytecodes.c" + #line 1368 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); PyDictObject *mdict = (PyDictObject *)GLOBALS(); @@ -2021,7 +1941,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 2025 "Python/generated_cases.c.h" + #line 1945 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2031,16 +1951,16 @@ } TARGET(DELETE_FAST) { - #line 1435 "Python/bytecodes.c" + #line 1385 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 2039 "Python/generated_cases.c.h" + #line 1959 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1441 "Python/bytecodes.c" + #line 1391 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -2049,12 +1969,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 2053 "Python/generated_cases.c.h" + #line 1973 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1452 "Python/bytecodes.c" + #line 1402 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -2065,37 +1985,21 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 2069 "Python/generated_cases.c.h" + #line 1989 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1465 "Python/bytecodes.c" + #line 1415 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); name = PyTuple_GET_ITEM(_PyFrame_GetCode(frame)->co_localsplusnames, oparg); - if (PyDict_CheckExact(class_dict)) { - value = PyDict_GetItemWithError(class_dict, name); - if (value != NULL) { - Py_INCREF(value); - } - else if (_PyErr_Occurred(tstate)) { - Py_DECREF(class_dict); - goto error; - } - } - else { - value = PyObject_GetItem(class_dict, name); - if (value == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - Py_DECREF(class_dict); - goto error; - } - _PyErr_Clear(tstate); - } + if (PyMapping_GetOptionalItem(class_dict, name, &value) < 0) { + Py_DECREF(class_dict); + goto error; } Py_DECREF(class_dict); if (!value) { @@ -2107,14 +2011,14 @@ } Py_INCREF(value); } - #line 2111 "Python/generated_cases.c.h" + #line 2015 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1502 "Python/bytecodes.c" + #line 1436 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2122,7 +2026,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2126 "Python/generated_cases.c.h" + #line 2030 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2130,18 +2034,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1512 "Python/bytecodes.c" + #line 1446 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2139 "Python/generated_cases.c.h" + #line 2043 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1519 "Python/bytecodes.c" + #line 1453 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2152,22 +2056,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2156 "Python/generated_cases.c.h" + #line 2060 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1532 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2165 "Python/generated_cases.c.h" + #line 2069 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1534 "Python/bytecodes.c" + #line 1468 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2171 "Python/generated_cases.c.h" + #line 2075 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2177,10 +2081,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1538 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2184 "Python/generated_cases.c.h" + #line 2088 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2190,10 +2094,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1543 "Python/bytecodes.c" + #line 1477 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2197 "Python/generated_cases.c.h" + #line 2101 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2203,7 +2107,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1548 "Python/bytecodes.c" + #line 1482 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2214,13 +2118,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2218 "Python/generated_cases.c.h" + #line 2122 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1559 "Python/bytecodes.c" + #line 1493 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2224 "Python/generated_cases.c.h" + #line 2128 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2229,13 +2133,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1566 "Python/bytecodes.c" + #line 1500 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2235 "Python/generated_cases.c.h" + #line 2139 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1568 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2239 "Python/generated_cases.c.h" + #line 2143 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2243,7 +2147,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1572 "Python/bytecodes.c" + #line 1506 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2258,7 +2162,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2262 "Python/generated_cases.c.h" + #line 2166 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2268,7 +2172,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1589 "Python/bytecodes.c" + #line 1523 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2276,13 +2180,13 @@ if (map == NULL) goto error; - #line 2280 "Python/generated_cases.c.h" + #line 2184 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1597 "Python/bytecodes.c" + #line 1531 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2286 "Python/generated_cases.c.h" + #line 2190 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2290,7 +2194,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1601 "Python/bytecodes.c" + #line 1535 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2315,10 +2219,8 @@ } else { /* do the same if locals() is not a dict */ - ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); + if (PyMapping_GetOptionalItem(LOCALS(), &_Py_ID(__annotations__), &ann_dict) < 0) goto error; if (ann_dict == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; - _PyErr_Clear(tstate); ann_dict = PyDict_New(); if (ann_dict == NULL) goto error; err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), @@ -2330,7 +2232,7 @@ Py_DECREF(ann_dict); } } - #line 2334 "Python/generated_cases.c.h" + #line 2236 "Python/generated_cases.c.h" DISPATCH(); } @@ -2338,7 +2240,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1643 "Python/bytecodes.c" + #line 1575 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2348,14 +2250,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2352 "Python/generated_cases.c.h" + #line 2254 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1653 "Python/bytecodes.c" + #line 1585 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2359 "Python/generated_cases.c.h" + #line 2261 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2363,7 +2265,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1657 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2371,12 +2273,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2375 "Python/generated_cases.c.h" + #line 2277 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1665 "Python/bytecodes.c" + #line 1597 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2380 "Python/generated_cases.c.h" + #line 2282 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2384,17 +2286,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1671 "Python/bytecodes.c" + #line 1603 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2393 "Python/generated_cases.c.h" + #line 2295 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1676 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2398 "Python/generated_cases.c.h" + #line 2300 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2403,25 +2305,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1682 "Python/bytecodes.c" + #line 1614 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2413 "Python/generated_cases.c.h" + #line 2315 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1690 "Python/bytecodes.c" + #line 1622 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2425 "Python/generated_cases.c.h" + #line 2327 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2432,7 +2334,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1704 "Python/bytecodes.c" + #line 1636 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2474,16 +2376,16 @@ } } } - #line 2478 "Python/generated_cases.c.h" + #line 2380 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1746 "Python/bytecodes.c" + #line 1678 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2487 "Python/generated_cases.c.h" + #line 2389 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2498,20 +2400,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1765 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2509 "Python/generated_cases.c.h" + #line 2411 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1772 "Python/bytecodes.c" + #line 1704 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2515 "Python/generated_cases.c.h" + #line 2417 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2526,7 +2428,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1776 "Python/bytecodes.c" + #line 1708 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2549,7 +2451,7 @@ res = res2; res2 = NULL; } - #line 2553 "Python/generated_cases.c.h" + #line 2455 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2563,7 +2465,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1817 "Python/bytecodes.c" + #line 1749 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2597,9 +2499,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2601 "Python/generated_cases.c.h" + #line 2503 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1851 "Python/bytecodes.c" + #line 1783 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2608,12 +2510,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2612 "Python/generated_cases.c.h" + #line 2514 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1860 "Python/bytecodes.c" + #line 1792 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2617 "Python/generated_cases.c.h" + #line 2519 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2627,7 +2529,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1869 "Python/bytecodes.c" + #line 1801 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2640,7 +2542,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2644 "Python/generated_cases.c.h" + #line 2546 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2655,7 +2557,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1885 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2668,7 +2570,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2672 "Python/generated_cases.c.h" + #line 2574 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2683,7 +2585,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1901 "Python/bytecodes.c" + #line 1833 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2710,7 +2612,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2714 "Python/generated_cases.c.h" + #line 2616 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2725,7 +2627,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1931 "Python/bytecodes.c" + #line 1863 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2735,7 +2637,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2739 "Python/generated_cases.c.h" + #line 2641 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2750,7 +2652,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1944 "Python/bytecodes.c" + #line 1876 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2762,7 +2664,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2766 "Python/generated_cases.c.h" + #line 2668 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2776,7 +2678,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1959 "Python/bytecodes.c" + #line 1891 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2800,7 +2702,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2804 "Python/generated_cases.c.h" + #line 2706 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2808,7 +2710,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1985 "Python/bytecodes.c" + #line 1917 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2834,7 +2736,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2838 "Python/generated_cases.c.h" + #line 2740 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2842,7 +2744,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2013 "Python/bytecodes.c" + #line 1945 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2860,7 +2762,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2864 "Python/generated_cases.c.h" + #line 2766 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2871,7 +2773,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 2033 "Python/bytecodes.c" + #line 1965 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2910,7 +2812,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2914 "Python/generated_cases.c.h" + #line 2816 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2921,7 +2823,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2074 "Python/bytecodes.c" + #line 2006 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2931,7 +2833,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2935 "Python/generated_cases.c.h" + #line 2837 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2943,7 +2845,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2093 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2956,10 +2858,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 2960 "Python/generated_cases.c.h" + #line 2862 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2106 "Python/bytecodes.c" + #line 2038 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2967,7 +2869,7 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 2971 "Python/generated_cases.c.h" + #line 2873 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2978,7 +2880,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2116 "Python/bytecodes.c" + #line 2048 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2990,7 +2892,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2994 "Python/generated_cases.c.h" + #line 2896 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3001,7 +2903,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2131 "Python/bytecodes.c" + #line 2063 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -3017,7 +2919,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 3021 "Python/generated_cases.c.h" + #line 2923 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3028,7 +2930,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2150 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -3041,7 +2943,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 3045 "Python/generated_cases.c.h" + #line 2947 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3052,14 +2954,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2165 "Python/bytecodes.c" + #line 2097 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 3058 "Python/generated_cases.c.h" + #line 2960 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2167 "Python/bytecodes.c" + #line 2099 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3063 "Python/generated_cases.c.h" + #line 2965 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3069,15 +2971,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2171 "Python/bytecodes.c" + #line 2103 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 3075 "Python/generated_cases.c.h" + #line 2977 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2173 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 3081 "Python/generated_cases.c.h" + #line 2983 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3088,12 +2990,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2178 "Python/bytecodes.c" + #line 2110 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 3094 "Python/generated_cases.c.h" + #line 2996 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2180 "Python/bytecodes.c" + #line 2112 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3101,10 +3003,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 3105 "Python/generated_cases.c.h" + #line 3007 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2188 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3113,7 +3015,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3117 "Python/generated_cases.c.h" + #line 3019 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3123,21 +3025,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2199 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3130 "Python/generated_cases.c.h" + #line 3032 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2202 "Python/bytecodes.c" + #line 2134 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3137 "Python/generated_cases.c.h" + #line 3039 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2207 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3141 "Python/generated_cases.c.h" + #line 3043 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3146,15 +3048,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2211 "Python/bytecodes.c" + #line 2143 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3153 "Python/generated_cases.c.h" + #line 3055 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2214 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3158 "Python/generated_cases.c.h" + #line 3060 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3163,25 +3065,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2218 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3171 "Python/generated_cases.c.h" + #line 3073 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2224 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" JUMPBY(oparg); - #line 3180 "Python/generated_cases.c.h" + #line 3082 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2228 "Python/bytecodes.c" + #line 2160 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); @@ -3200,12 +3102,12 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3204 "Python/generated_cases.c.h" + #line 3106 "Python/generated_cases.c.h" DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2259 "Python/bytecodes.c" + #line 2191 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); PyCodeObject *code = _PyFrame_GetCode(frame); @@ -3220,25 +3122,25 @@ goto resume_with_error; } goto resume_frame; - #line 3224 "Python/generated_cases.c.h" + #line 3126 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2276 "Python/bytecodes.c" + #line 2208 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3232 "Python/generated_cases.c.h" + #line 3134 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2281 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3242 "Python/generated_cases.c.h" + #line 3144 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3248,25 +3150,25 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2286 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3258 "Python/generated_cases.c.h" + #line 3160 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2292 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" } - #line 3262 "Python/generated_cases.c.h" + #line 3164 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2281 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3270 "Python/generated_cases.c.h" + #line 3172 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); @@ -3277,52 +3179,52 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2286 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3287 "Python/generated_cases.c.h" + #line 3189 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2292 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" } - #line 3291 "Python/generated_cases.c.h" + #line 3193 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2276 "Python/bytecodes.c" + #line 2208 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3299 "Python/generated_cases.c.h" + #line 3201 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2300 "Python/bytecodes.c" + #line 2232 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3313 "Python/generated_cases.c.h" + #line 3215 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2309 "Python/bytecodes.c" + #line 2241 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3326 "Python/generated_cases.c.h" + #line 3228 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3333,16 +3235,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2317 "Python/bytecodes.c" + #line 2249 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3342 "Python/generated_cases.c.h" + #line 3244 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2322 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3350,7 +3252,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3354 "Python/generated_cases.c.h" + #line 3256 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3359,10 +3261,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2332 "Python/bytecodes.c" + #line 2264 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3366 "Python/generated_cases.c.h" + #line 3268 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3371,10 +3273,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2337 "Python/bytecodes.c" + #line 2269 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3378 "Python/generated_cases.c.h" + #line 3280 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3384,11 +3286,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2342 "Python/bytecodes.c" + #line 2274 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3392 "Python/generated_cases.c.h" + #line 3294 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3397,14 +3299,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2348 "Python/bytecodes.c" + #line 2280 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3404 "Python/generated_cases.c.h" + #line 3306 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2351 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3408 "Python/generated_cases.c.h" + #line 3310 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3412,7 +3314,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2355 "Python/bytecodes.c" + #line 2287 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3435,11 +3337,11 @@ if (iter == NULL) { goto error; } - #line 3439 "Python/generated_cases.c.h" + #line 3341 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2378 "Python/bytecodes.c" + #line 2310 "Python/bytecodes.c" } - #line 3443 "Python/generated_cases.c.h" + #line 3345 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3449,7 +3351,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2396 "Python/bytecodes.c" + #line 2328 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3481,7 +3383,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3485 "Python/generated_cases.c.h" + #line 3387 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3489,7 +3391,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2430 "Python/bytecodes.c" + #line 2362 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3515,14 +3417,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3519 "Python/generated_cases.c.h" + #line 3421 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2458 "Python/bytecodes.c" + #line 2390 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3543,7 +3445,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3547 "Python/generated_cases.c.h" + #line 3449 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3553,7 +3455,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2481 "Python/bytecodes.c" + #line 2413 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3574,7 +3476,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3578 "Python/generated_cases.c.h" + #line 3480 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3584,7 +3486,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2504 "Python/bytecodes.c" + #line 2436 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3603,7 +3505,7 @@ if (next == NULL) { goto error; } - #line 3607 "Python/generated_cases.c.h" + #line 3509 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3612,7 +3514,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2525 "Python/bytecodes.c" + #line 2457 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3628,14 +3530,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3632 "Python/generated_cases.c.h" + #line 3534 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2543 "Python/bytecodes.c" + #line 2475 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3658,16 +3560,16 @@ Py_DECREF(enter); goto error; } - #line 3662 "Python/generated_cases.c.h" + #line 3564 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2566 "Python/bytecodes.c" + #line 2498 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3671 "Python/generated_cases.c.h" + #line 3573 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3678,7 +3580,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2575 "Python/bytecodes.c" + #line 2507 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3704,16 +3606,16 @@ Py_DECREF(enter); goto error; } - #line 3708 "Python/generated_cases.c.h" + #line 3610 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2601 "Python/bytecodes.c" + #line 2533 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3717 "Python/generated_cases.c.h" + #line 3619 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3725,7 +3627,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2610 "Python/bytecodes.c" + #line 2542 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3746,7 +3648,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3750 "Python/generated_cases.c.h" + #line 3652 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3755,7 +3657,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2649 "Python/bytecodes.c" + #line 2581 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3765,7 +3667,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3769 "Python/generated_cases.c.h" + #line 3671 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3779,7 +3681,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2661 "Python/bytecodes.c" + #line 2593 "Python/bytecodes.c" assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); @@ -3796,7 +3698,7 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - #line 3800 "Python/generated_cases.c.h" + #line 3702 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3810,7 +3712,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2680 "Python/bytecodes.c" + #line 2612 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3820,7 +3722,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3824 "Python/generated_cases.c.h" + #line 3726 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3835,7 +3737,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2692 "Python/bytecodes.c" + #line 2624 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3848,11 +3750,11 @@ keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3852 "Python/generated_cases.c.h" + #line 3754 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2705 "Python/bytecodes.c" + #line 2637 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3856 "Python/generated_cases.c.h" + #line 3758 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3866,7 +3768,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2709 "Python/bytecodes.c" + #line 2641 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3874,11 +3776,11 @@ assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3878 "Python/generated_cases.c.h" + #line 3780 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2717 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3882 "Python/generated_cases.c.h" + #line 3784 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3892,7 +3794,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2721 "Python/bytecodes.c" + #line 2653 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3906,7 +3808,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3910 "Python/generated_cases.c.h" + #line 3812 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3915,16 +3817,16 @@ } TARGET(KW_NAMES) { - #line 2737 "Python/bytecodes.c" + #line 2669 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3923 "Python/generated_cases.c.h" + #line 3825 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2743 "Python/bytecodes.c" + #line 2675 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3937,7 +3839,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3941 "Python/generated_cases.c.h" + #line 3843 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3947,7 +3849,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2789 "Python/bytecodes.c" + #line 2721 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4029,7 +3931,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4033 "Python/generated_cases.c.h" + #line 3935 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4041,7 +3943,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2877 "Python/bytecodes.c" + #line 2809 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -4051,7 +3953,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 4055 "Python/generated_cases.c.h" + #line 3957 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -4060,7 +3962,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2889 "Python/bytecodes.c" + #line 2821 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4086,7 +3988,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4090 "Python/generated_cases.c.h" + #line 3992 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4094,7 +3996,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2917 "Python/bytecodes.c" + #line 2849 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4130,7 +4032,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4134 "Python/generated_cases.c.h" + #line 4036 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4138,7 +4040,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2955 "Python/bytecodes.c" + #line 2887 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4148,7 +4050,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4152 "Python/generated_cases.c.h" + #line 4054 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4161,7 +4063,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2967 "Python/bytecodes.c" + #line 2899 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4172,7 +4074,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4176 "Python/generated_cases.c.h" + #line 4078 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4186,7 +4088,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2981 "Python/bytecodes.c" + #line 2913 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4197,7 +4099,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4201 "Python/generated_cases.c.h" + #line 4103 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4210,7 +4112,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2995 "Python/bytecodes.c" + #line 2927 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4261,12 +4163,12 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4265 "Python/generated_cases.c.h" + #line 4167 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3048 "Python/bytecodes.c" + #line 2980 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4274,7 +4176,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4278 "Python/generated_cases.c.h" + #line 4180 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4284,7 +4186,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3058 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4306,7 +4208,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4310 "Python/generated_cases.c.h" + #line 4212 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4320,7 +4222,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3083 "Python/bytecodes.c" + #line 3015 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4348,7 +4250,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4352 "Python/generated_cases.c.h" + #line 4254 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4362,7 +4264,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3114 "Python/bytecodes.c" + #line 3046 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4394,7 +4296,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4398 "Python/generated_cases.c.h" + #line 4300 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4408,7 +4310,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3149 "Python/bytecodes.c" + #line 3081 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4440,7 +4342,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4444 "Python/generated_cases.c.h" + #line 4346 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4454,7 +4356,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3184 "Python/bytecodes.c" + #line 3116 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4479,7 +4381,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4483 "Python/generated_cases.c.h" + #line 4385 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4492,7 +4394,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3211 "Python/bytecodes.c" + #line 3143 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4519,7 +4421,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4523 "Python/generated_cases.c.h" + #line 4425 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4531,7 +4433,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3241 "Python/bytecodes.c" + #line 3173 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4549,14 +4451,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4553 "Python/generated_cases.c.h" + #line 4455 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3261 "Python/bytecodes.c" + #line 3193 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4587,7 +4489,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4591 "Python/generated_cases.c.h" + #line 4493 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4600,7 +4502,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3295 "Python/bytecodes.c" + #line 3227 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4629,7 +4531,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4633 "Python/generated_cases.c.h" + #line 4535 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4642,7 +4544,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3327 "Python/bytecodes.c" + #line 3259 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4671,7 +4573,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4675 "Python/generated_cases.c.h" + #line 4577 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4684,7 +4586,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3359 "Python/bytecodes.c" + #line 3291 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4712,7 +4614,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4716 "Python/generated_cases.c.h" + #line 4618 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4722,9 +4624,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3390 "Python/bytecodes.c" + #line 3322 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4728 "Python/generated_cases.c.h" + #line 4630 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4733,7 +4635,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3394 "Python/bytecodes.c" + #line 3326 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4795,14 +4697,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4799 "Python/generated_cases.c.h" + #line 4701 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3456 "Python/bytecodes.c" + #line 3388 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4806 "Python/generated_cases.c.h" + #line 4708 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4813,7 +4715,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3462 "Python/bytecodes.c" + #line 3394 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4825,7 +4727,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4829 "Python/generated_cases.c.h" + #line 4731 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4833,7 +4735,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3476 "Python/bytecodes.c" + #line 3408 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4858,14 +4760,14 @@ default: Py_UNREACHABLE(); } - #line 4862 "Python/generated_cases.c.h" + #line 4764 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3503 "Python/bytecodes.c" + #line 3435 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4886,7 +4788,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4890 "Python/generated_cases.c.h" + #line 4792 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4894,15 +4796,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3526 "Python/bytecodes.c" + #line 3458 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4900 "Python/generated_cases.c.h" + #line 4802 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3528 "Python/bytecodes.c" + #line 3460 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4906 "Python/generated_cases.c.h" + #line 4808 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4912,14 +4814,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3532 "Python/bytecodes.c" + #line 3464 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4923 "Python/generated_cases.c.h" + #line 4825 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4927,7 +4829,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3541 "Python/bytecodes.c" + #line 3473 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4938,7 +4840,7 @@ else { res = value; } - #line 4942 "Python/generated_cases.c.h" + #line 4844 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4947,12 +4849,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3554 "Python/bytecodes.c" + #line 3486 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4956 "Python/generated_cases.c.h" + #line 4858 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4961,10 +4863,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3561 "Python/bytecodes.c" + #line 3493 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4968 "Python/generated_cases.c.h" + #line 4870 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4976,7 +4878,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3566 "Python/bytecodes.c" + #line 3498 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4991,12 +4893,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4995 "Python/generated_cases.c.h" + #line 4897 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3581 "Python/bytecodes.c" + #line 3513 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 5000 "Python/generated_cases.c.h" + #line 4902 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -5006,16 +4908,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3586 "Python/bytecodes.c" + #line 3518 "Python/bytecodes.c" assert(oparg >= 2); - #line 5012 "Python/generated_cases.c.h" + #line 4914 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3590 "Python/bytecodes.c" + #line 3522 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -5027,48 +4929,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 5031 "Python/generated_cases.c.h" + #line 4933 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3604 "Python/bytecodes.c" + #line 3536 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 5037 "Python/generated_cases.c.h" + #line 4939 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3608 "Python/bytecodes.c" + #line 3540 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 5045 "Python/generated_cases.c.h" + #line 4947 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3613 "Python/bytecodes.c" + #line 3545 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5056 "Python/generated_cases.c.h" + #line 4958 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3621 "Python/bytecodes.c" + #line 3553 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5067 "Python/generated_cases.c.h" + #line 4969 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3629 "Python/bytecodes.c" + #line 3561 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5080,12 +4982,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5084 "Python/generated_cases.c.h" + #line 4986 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3643 "Python/bytecodes.c" + #line 3575 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5097,30 +4999,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5101 "Python/generated_cases.c.h" + #line 5003 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3657 "Python/bytecodes.c" + #line 3589 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5112 "Python/generated_cases.c.h" + #line 5014 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3665 "Python/bytecodes.c" + #line 3597 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5119 "Python/generated_cases.c.h" + #line 5021 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3670 "Python/bytecodes.c" + #line 3602 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5126 "Python/generated_cases.c.h" + #line 5028 "Python/generated_cases.c.h" } diff --git a/Python/import.c b/Python/import.c index fcc0346e7f15af..7ce89cdf9a91a0 100644 --- a/Python/import.c +++ b/Python/import.c @@ -249,16 +249,7 @@ import_get_module(PyThreadState *tstate, PyObject *name) PyObject *m; Py_INCREF(modules); - if (PyDict_CheckExact(modules)) { - m = PyDict_GetItemWithError(modules, name); /* borrowed */ - Py_XINCREF(m); - } - else { - m = PyObject_GetItem(modules, name); - if (m == NULL && _PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } - } + (void)PyMapping_GetOptionalItem(modules, name, &m); Py_DECREF(modules); return m; } @@ -322,18 +313,7 @@ import_add_module(PyThreadState *tstate, PyObject *name) } PyObject *m; - if (PyDict_CheckExact(modules)) { - m = Py_XNewRef(PyDict_GetItemWithError(modules, name)); - } - else { - m = PyObject_GetItem(modules, name); - // For backward-compatibility we copy the behavior - // of PyDict_GetItemWithError(). - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - _PyErr_Clear(tstate); - } - } - if (_PyErr_Occurred(tstate)) { + if (PyMapping_GetOptionalItem(modules, name, &m) < 0) { return NULL; } if (m != NULL && PyModule_Check(m)) { From fc7ff1af457e27b7d9752600b3436641be90f598 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Tue, 11 Jul 2023 22:09:04 +0200 Subject: [PATCH 357/446] gh-96165: Clarify omitting the FROM clause in SQLite queries (#106513) --- Doc/library/sqlite3.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index bc69387fca8a93..f6a8714519f59f 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -2519,6 +2519,13 @@ Queries now return :class:`!Row` objects: >>> row["RADIUS"] # Column names are case-insensitive. 6378 +.. note:: + + The ``FROM`` clause can be omitted in the ``SELECT`` statement, as in the + above example. In such cases, SQLite returns a single row with columns + defined by expressions, e.g. literals, with the given aliases + ``expr AS alias``. + You can create a custom :attr:`~Cursor.row_factory` that returns each row as a :class:`dict`, with column names mapped to values: From f520804b039df0d87fb9df6f1fed2a9bc9df8d61 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Tue, 11 Jul 2023 22:18:19 +0200 Subject: [PATCH 358/446] gh-96165: Clarify passing ":memory:" in sqlite3.connect() (#106451) --- Doc/library/sqlite3.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index f6a8714519f59f..356888d64b8876 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -266,8 +266,9 @@ Module functions :param database: The path to the database file to be opened. - Pass ``":memory:"`` to open a connection to a database that is - in RAM instead of on disk. + You can pass ``":memory:"`` to create an `SQLite database existing only + in memory `_, and open a connection + to it. :type database: :term:`path-like object` :param float timeout: From 3590c45a3d564b3182ae21d899bae81c49d685a2 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 11 Jul 2023 23:25:41 +0300 Subject: [PATCH 359/446] gh-104584: readability improvements in optimizer.c (#106641) --- Python/optimizer.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index 8d4162b44c2f35..e2b92e68d39e1f 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -3,6 +3,7 @@ #include "pycore_interp.h" #include "pycore_opcode.h" #include "opcode_metadata.h" +#include "pycore_opcode_utils.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_uops.h" #include "cpython/optimizer.h" @@ -10,6 +11,8 @@ #include #include +#define MAX_EXECUTORS_SIZE 256 + static bool has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) { @@ -19,7 +22,7 @@ has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) if (code->co_executors == NULL) { return true; } - return code->co_executors->size < 256; + return code->co_executors->size < MAX_EXECUTORS_SIZE; } static int32_t @@ -34,7 +37,7 @@ get_index_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) if (old != NULL) { size = old->size; capacity = old->capacity; - assert(size < 256); + assert(size < MAX_EXECUTORS_SIZE); } assert(size <= capacity); if (size == capacity) { @@ -74,7 +77,7 @@ insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorO executor->vm_data.opcode = instr->op.code; executor->vm_data.oparg = instr->op.arg; code->co_executors->executors[index] = executor; - assert(index < 256); + assert(index < MAX_EXECUTORS_SIZE); instr->op.code = ENTER_EXECUTOR; instr->op.arg = index; code->co_executors->size++; @@ -307,7 +310,7 @@ uop_dealloc(_PyUOpExecutorObject *self) { static const char * uop_name(int index) { - if (index < 256) { + if (index <= MAX_REAL_OPCODE) { return _PyOpcode_OpName[index]; } return _PyOpcode_uop_name[index]; @@ -391,17 +394,20 @@ translate_bytecode_to_trace( #define ADD_TO_TRACE(OPCODE, OPERAND) \ DPRINTF(2, \ " ADD_TO_TRACE(%s, %" PRIu64 ")\n", \ - (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)], \ + uop_name(OPCODE), \ (uint64_t)(OPERAND)); \ assert(trace_length < max_length); \ trace[trace_length].opcode = (OPCODE); \ trace[trace_length].operand = (OPERAND); \ trace_length++; +#define INSTR_IP(INSTR, CODE) \ + ((long)((INSTR) - ((_Py_CODEUNIT *)(CODE)->co_code_adaptive))) + #define ADD_TO_STUB(INDEX, OPCODE, OPERAND) \ DPRINTF(2, " ADD_TO_STUB(%d, %s, %" PRIu64 ")\n", \ (INDEX), \ - (OPCODE) < 256 ? _PyOpcode_OpName[(OPCODE)] : _PyOpcode_uop_name[(OPCODE)], \ + uop_name(OPCODE), \ (uint64_t)(OPERAND)); \ trace[(INDEX)].opcode = (OPCODE); \ trace[(INDEX)].operand = (OPERAND); @@ -411,10 +417,10 @@ translate_bytecode_to_trace( PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + 2 * INSTR_IP(initial_instr, code)); for (;;) { - ADD_TO_TRACE(SAVE_IP, instr - (_Py_CODEUNIT *)code->co_code_adaptive); + ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code)); int opcode = instr->op.code; int oparg = instr->op.arg; int extras = 0; @@ -448,8 +454,7 @@ translate_bytecode_to_trace( int uopcode = opcode == POP_JUMP_IF_TRUE ? _POP_JUMP_IF_TRUE : _POP_JUMP_IF_FALSE; ADD_TO_TRACE(uopcode, max_length); - ADD_TO_STUB(max_length, SAVE_IP, - target_instr - (_Py_CODEUNIT *)code->co_code_adaptive); + ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(target_instr, code)); ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0); break; } @@ -474,9 +479,7 @@ translate_bytecode_to_trace( // Reserve space for nuops (+ SAVE_IP + EXIT_TRACE) int nuops = expansion->nuops; if (trace_length + nuops + 2 > max_length) { - DPRINTF(1, - "Ran out of space for %s\n", - opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]); + DPRINTF(1, "Ran out of space for %s\n", uop_name(opcode)); goto done; } for (int i = 0; i < nuops; i++) { @@ -522,9 +525,7 @@ translate_bytecode_to_trace( } break; } - DPRINTF(2, - "Unsupported opcode %s\n", - opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode]); + DPRINTF(2, "Unsupported opcode %s\n", uop_name(opcode)); goto done; // Break out of loop } } @@ -542,7 +543,7 @@ translate_bytecode_to_trace( PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive), + 2 * INSTR_IP(initial_instr, code), trace_length); if (max_length < buffer_size && trace_length < max_length) { // Move the stubs back to be immediately after the main trace @@ -576,7 +577,7 @@ translate_bytecode_to_trace( PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, - 2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive)); + 2 * INSTR_IP(initial_instr, code)); } return 0; From d0972c77aa1cd5fe27618e82c10141a2bf157476 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 11 Jul 2023 22:21:14 +0100 Subject: [PATCH 360/446] gh-104050: Argument Clinic: Annotate the `Block` class (#106519) --- Tools/clinic/clinic.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 19c5f573920cb9..12ab633388485e 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -759,7 +759,7 @@ def parse_line(self, line: str) -> None: def render( self, clinic: Clinic | None, - signatures: Iterable[Function] + signatures: Iterable[Module | Class | Function] ) -> str: function = None for o in signatures: @@ -1633,6 +1633,7 @@ def create_regex( return re.compile(pattern) +@dc.dataclass(slots=True, repr=False) class Block: r""" Represents a single block of text embedded in @@ -1679,18 +1680,16 @@ class Block: "preindent" would be "____" and "indent" would be "__". """ - def __init__(self, input, dsl_name=None, signatures=None, output=None, indent='', preindent=''): - assert isinstance(input, str) - self.input = input - self.dsl_name = dsl_name - self.signatures = signatures or [] - self.output = output - self.indent = indent - self.preindent = preindent + input: str + dsl_name: str | None = None + signatures: list[Module | Class | Function] = dc.field(default_factory=list) + output: Any = None # TODO: Very dynamic; probably untypeable in its current form? + indent: str = '' + preindent: str = '' - def __repr__(self): + def __repr__(self) -> str: dsl_name = self.dsl_name or "text" - def summarize(s): + def summarize(s: object) -> str: s = repr(s) if len(s) > 30: return s[:26] + "..." + s[0] @@ -4619,10 +4618,13 @@ def state_modulename_name(self, line: str | None) -> None: if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") - self.function = existing_function.copy(name=function_name, full_name=full_name, module=module, cls=cls, c_basename=c_basename, docstring='') - - self.block.signatures.append(self.function) - (cls or module).functions.append(self.function) + function = existing_function.copy( + name=function_name, full_name=full_name, module=module, + cls=cls, c_basename=c_basename, docstring='' + ) + self.function = function + self.block.signatures.append(function) + (cls or module).functions.append(function) self.next(self.state_function_docstring) return From da86db56cb595fdbeda8b57a1ec03b1dd80ad1f0 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 11 Jul 2023 15:13:57 -0700 Subject: [PATCH 361/446] gh-106529: Implement JUMP_FORWARD in uops (with test) (#106651) Note that this may generate two SAVE_IP uops in a row. Removing unneeded SAVE_IP uops is the optimizer's job. --- Lib/test/test_capi/test_misc.py | 25 +++++++++++++++++++++++++ Python/optimizer.c | 7 +++++++ 2 files changed, 32 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9cbd5506bf6dea..9c14a501875b6d 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2553,6 +2553,7 @@ def testfunc(n): i = 0 while i < n: i += 1 + opt = _testinternalcapi.get_uop_optimizer() with temporary_optimizer(opt): testfunc(10) @@ -2562,6 +2563,30 @@ def testfunc(n): uops = {opname for opname, _ in ex} self.assertIn("JUMP_TO_TOP", uops) + def test_jump_forward(self): + def testfunc(n): + a = 0 + while a < n: + if a < 0: + a = -a + else: + a = +a + a += 1 + return a + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc(10) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + # for i, (opname, oparg) in enumerate(ex): + # print(f"{i:4d}: {opname:<20s} {oparg:4d}") + uops = {opname for opname, _ in ex} + # Since there is no JUMP_FORWARD instruction, + # look for indirect evidence: the += operator + self.assertIn("_BINARY_OP_ADD_INT", uops) + if __name__ == "__main__": unittest.main() diff --git a/Python/optimizer.c b/Python/optimizer.c index e2b92e68d39e1f..7fc40e66057d30 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -472,6 +472,13 @@ translate_bytecode_to_trace( goto done; } + case JUMP_FORWARD: + { + // This will emit two SAVE_IP instructions; leave it to the optimizer + instr += oparg; + break; + } + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; From de827322ca47e51d52ff44536a7c3fd44648383a Mon Sep 17 00:00:00 2001 From: Ijtaba Hussain Date: Tue, 11 Jul 2023 23:22:18 +0100 Subject: [PATCH 362/446] gh-103186: In test_tools.freeze, fetch CONFIG_ARGS from original source directory (#103213) Fetch CONFIG_ARGS from the original source directory, instead of from the copied source tree. When "make clean" is executed in the copied source tree, the build directory is cleared and the configure argument lookup fails. However, the original source directory still contains this information. --- .../Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst | 2 ++ Tools/freeze/test/freeze.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst b/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst new file mode 100644 index 00000000000000..7e28ba6963216a --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-04-05-07-19-36.gh-issue-103186.yEozgK.rst @@ -0,0 +1,2 @@ +``freeze`` now fetches ``CONFIG_ARGS`` from the original CPython instance +the Makefile uses to call utility scripts. Patch by Ijtaba Hussain. diff --git a/Tools/freeze/test/freeze.py b/Tools/freeze/test/freeze.py index f6a5adb4519fdb..92e97cb261719c 100644 --- a/Tools/freeze/test/freeze.py +++ b/Tools/freeze/test/freeze.py @@ -153,7 +153,7 @@ def prepare(script=None, outdir=None): print(f'configuring python in {builddir}...') cmd = [ os.path.join(srcdir, 'configure'), - *shlex.split(get_config_var(srcdir, 'CONFIG_ARGS') or ''), + *shlex.split(get_config_var(SRCDIR, 'CONFIG_ARGS') or ''), ] ensure_opt(cmd, 'cache-file', os.path.join(outdir, 'python-config.cache')) prefix = os.path.join(outdir, 'python-installation') From 7ce3ea4906986c2bab784c878d31c57b14ee1945 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 12 Jul 2023 00:08:28 +0100 Subject: [PATCH 363/446] gh-104683: Argument clinic: Minor readability improvements for `Destination.__init__` (#106652) --- Tools/clinic/clinic.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 12ab633388485e..a0cf50b29c978d 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1959,14 +1959,19 @@ def __init__(self, name, type, clinic, *args): self.name = name self.type = type self.clinic = clinic + self.buffers = BufferSeries() + valid_types = ('buffer', 'file', 'suppress') if type not in valid_types: - fail("Invalid destination type " + repr(type) + " for " + name + " , must be " + ', '.join(valid_types)) + fail( + f"Invalid destination type {type!r} for {name}, " + f"must be {', '.join(valid_types)}" + ) extra_arguments = 1 if type == "file" else 0 if len(args) < extra_arguments: - fail("Not enough arguments for destination " + name + " new " + type) + fail(f"Not enough arguments for destination {name} new {type}") if len(args) > extra_arguments: - fail("Too many arguments for destination " + name + " new " + type) + fail(f"Too many arguments for destination {name} new {type}") if type =='file': d = {} filename = clinic.filename @@ -1979,8 +1984,6 @@ def __init__(self, name, type, clinic, *args): d['basename_root'], d['basename_extension'] = os.path.splitext(filename) self.filename = args[0].format_map(d) - self.buffers = BufferSeries() - def __repr__(self): if self.type == 'file': file_repr = " " + repr(self.filename) From e8ab0096a583184fe24dfbc39eff70d270c8e6f4 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 12 Jul 2023 05:35:24 +0300 Subject: [PATCH 364/446] Add Plausible for docs metrics (#106644) --- Doc/tools/templates/layout.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/tools/templates/layout.html b/Doc/tools/templates/layout.html index 9632ad50a51bf0..18a49271df5f20 100644 --- a/Doc/tools/templates/layout.html +++ b/Doc/tools/templates/layout.html @@ -26,6 +26,7 @@ {% endblock %} {% block extrahead %} + {% if builder != "htmlhelp" %} {% if pagename == 'whatsnew/changelog' and not embedded %} From be1b968dc1e63c3c68e161ddc5a05eb064833440 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 12 Jul 2023 08:57:10 +0300 Subject: [PATCH 365/446] gh-106521: Remove _PyObject_LookupAttr() function (GH-106642) --- Include/cpython/object.h | 1 - Modules/_abc.c | 4 +- Modules/_asynciomodule.c | 4 +- Modules/_csv.c | 2 +- Modules/_ctypes/_ctypes.c | 22 +- Modules/_ctypes/callproc.c | 2 +- Modules/_ctypes/stgdict.c | 6 +- Modules/_datetimemodule.c | 2 +- Modules/_elementtree.c | 2 +- Modules/_io/bufferedio.c | 4 +- Modules/_io/fileio.c | 2 +- Modules/_io/iobase.c | 8 +- Modules/_io/textio.c | 12 +- Modules/_pickle.c | 38 +-- Modules/_sqlite/microprotocols.c | 4 +- Modules/_threadmodule.c | 2 +- Modules/arraymodule.c | 2 +- Modules/itertoolsmodule.c | 2 +- Modules/pyexpat.c | 2 +- Objects/abstract.c | 8 +- Objects/call.c | 2 +- Objects/classobject.c | 6 +- Objects/descrobject.c | 2 +- Objects/dictobject.c | 2 +- Objects/exceptions.c | 4 +- Objects/fileobject.c | 2 +- Objects/funcobject.c | 2 +- Objects/genericaliasobject.c | 22 +- Objects/genobject.c | 4 +- Objects/moduleobject.c | 2 +- Objects/odictobject.c | 4 +- Objects/typeobject.c | 22 +- Objects/unionobject.c | 8 +- Parser/asdl_c.py | 6 +- Python/Python-ast.c | 444 +++++++++++++++---------------- Python/_warnings.c | 4 +- Python/bltinmodule.c | 10 +- Python/ceval.c | 6 +- Python/codecs.c | 2 +- Python/errors.c | 4 +- Python/import.c | 2 +- Python/intrinsics.c | 4 +- Python/pythonrun.c | 4 +- Python/suggestions.c | 2 +- Python/sysmodule.c | 4 +- 45 files changed, 351 insertions(+), 352 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index ba30c567c40ebd..cd421b4f7e0d49 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -294,7 +294,6 @@ PyAPI_FUNC(int) _PyObject_IsFreed(PyObject *); PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *); PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, _Py_Identifier *); PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, _Py_Identifier *, PyObject *); -#define _PyObject_LookupAttr PyObject_GetOptionalAttr PyAPI_FUNC(int) _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); diff --git a/Modules/_abc.c b/Modules/_abc.c index 93c0a93c442cdb..8a3aa9cb88880f 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -361,7 +361,7 @@ compute_abstract_methods(PyObject *self) PyObject *item = PyTuple_GET_ITEM(bases, pos); // borrowed PyObject *base_abstracts, *iter; - if (_PyObject_LookupAttr(item, &_Py_ID(__abstractmethods__), + if (PyObject_GetOptionalAttr(item, &_Py_ID(__abstractmethods__), &base_abstracts) < 0) { goto error; } @@ -375,7 +375,7 @@ compute_abstract_methods(PyObject *self) Py_DECREF(base_abstracts); PyObject *key, *value; while ((key = PyIter_Next(iter))) { - if (_PyObject_LookupAttr(self, key, &value) < 0) { + if (PyObject_GetOptionalAttr(self, key, &value) < 0) { Py_DECREF(key); Py_DECREF(iter); goto error; diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 3b0550279fb49c..ef9f7f8902e09e 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -248,7 +248,7 @@ get_future_loop(asyncio_state *state, PyObject *fut) return Py_NewRef(loop); } - if (_PyObject_LookupAttr(fut, &_Py_ID(get_loop), &getloop) < 0) { + if (PyObject_GetOptionalAttr(fut, &_Py_ID(get_loop), &getloop) < 0) { return NULL; } if (getloop != NULL) { @@ -2966,7 +2966,7 @@ task_step_handle_result_impl(asyncio_state *state, TaskObj *task, PyObject *resu } /* Check if `result` is a Future-compatible object */ - if (_PyObject_LookupAttr(result, &_Py_ID(_asyncio_future_blocking), &o) < 0) { + if (PyObject_GetOptionalAttr(result, &_Py_ID(_asyncio_future_blocking), &o) < 0) { goto fail; } if (o != NULL && o != Py_None) { diff --git a/Modules/_csv.c b/Modules/_csv.c index 5b501af449f18d..c36d9805a12841 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1450,7 +1450,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) Py_DECREF(self); return NULL; } - if (_PyObject_LookupAttr(output_file, + if (PyObject_GetOptionalAttr(output_file, module_state->str_write, &self->write) < 0) { Py_DECREF(self); diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index a9d8a2b9cb4ad7..7624c15ac522da 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -851,7 +851,7 @@ CDataType_from_param(PyObject *type, PyObject *value) return NULL; } - if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { + if (PyObject_GetOptionalAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { return NULL; } if (as_parameter) { @@ -1495,7 +1495,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict = NULL; type_attr = NULL; - if (_PyObject_LookupAttr((PyObject *)result, &_Py_ID(_length_), &length_attr) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_length_), &length_attr) < 0) { goto error; } if (!length_attr) { @@ -1528,7 +1528,7 @@ PyCArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) goto error; } - if (_PyObject_LookupAttr((PyObject *)result, &_Py_ID(_type_), &type_attr) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &type_attr) < 0) { goto error; } if (!type_attr) { @@ -1720,7 +1720,7 @@ c_wchar_p_from_param(PyObject *type, PyObject *value) } } - if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { + if (PyObject_GetOptionalAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { return NULL; } if (as_parameter) { @@ -1784,7 +1784,7 @@ c_char_p_from_param(PyObject *type, PyObject *value) } } - if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { + if (PyObject_GetOptionalAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { return NULL; } if (as_parameter) { @@ -1919,7 +1919,7 @@ c_void_p_from_param(PyObject *type, PyObject *value) } } - if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { + if (PyObject_GetOptionalAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { return NULL; } if (as_parameter) { @@ -2054,7 +2054,7 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (result == NULL) return NULL; - if (_PyObject_LookupAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) { return NULL; } if (!proto) { @@ -2266,7 +2266,7 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value) PyObject *exc = PyErr_GetRaisedException(); Py_DECREF(parg); - if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { + if (PyObject_GetOptionalAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { Py_XDECREF(exc); return NULL; } @@ -2429,7 +2429,7 @@ converters_from_argtypes(PyObject *ob) } */ - if (_PyObject_LookupAttr(tp, &_Py_ID(from_param), &cnv) <= 0) { + if (PyObject_GetOptionalAttr(tp, &_Py_ID(from_param), &cnv) <= 0) { Py_DECREF(converters); Py_DECREF(ob); if (!PyErr_Occurred()) { @@ -2489,7 +2489,7 @@ make_funcptrtype_dict(StgDictObject *stgdict) return -1; } stgdict->restype = Py_NewRef(ob); - if (_PyObject_LookupAttr(ob, &_Py_ID(_check_retval_), + if (PyObject_GetOptionalAttr(ob, &_Py_ID(_check_retval_), &stgdict->checker) < 0) { return -1; @@ -3275,7 +3275,7 @@ PyCFuncPtr_set_restype(PyCFuncPtrObject *self, PyObject *ob, void *Py_UNUSED(ign "restype must be a type, a callable, or None"); return -1; } - if (_PyObject_LookupAttr(ob, &_Py_ID(_check_retval_), &checker) < 0) { + if (PyObject_GetOptionalAttr(ob, &_Py_ID(_check_retval_), &checker) < 0) { return -1; } oldchecker = self->checker; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index d2fe525dd4d396..b3831ae7119a56 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -727,7 +727,7 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa) { PyObject *arg; - if (_PyObject_LookupAttr(obj, &_Py_ID(_as_parameter_), &arg) < 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(_as_parameter_), &arg) < 0) { return -1; } /* Which types should we exactly allow here? diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index b1b2bac1455e67..3348ebd6593d2f 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -295,7 +295,7 @@ MakeAnonFields(PyObject *type) PyObject *anon_names; Py_ssize_t i; - if (_PyObject_LookupAttr(type, &_Py_ID(_anonymous_), &anon) < 0) { + if (PyObject_GetOptionalAttr(type, &_Py_ID(_anonymous_), &anon) < 0) { return -1; } if (anon == NULL) { @@ -385,7 +385,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct if (fields == NULL) return 0; - if (_PyObject_LookupAttr(type, &_Py_ID(_swappedbytes_), &tmp) < 0) { + if (PyObject_GetOptionalAttr(type, &_Py_ID(_swappedbytes_), &tmp) < 0) { return -1; } if (tmp) { @@ -396,7 +396,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct big_endian = PY_BIG_ENDIAN; } - if (_PyObject_LookupAttr(type, &_Py_ID(_pack_), &tmp) < 0) { + if (PyObject_GetOptionalAttr(type, &_Py_ID(_pack_), &tmp) < 0) { return -1; } if (tmp) { diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index db2d339fc36db4..b8cb0c012fd537 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -3791,7 +3791,7 @@ tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *args, *state; PyObject *getinitargs; - if (_PyObject_LookupAttr(self, &_Py_ID(__getinitargs__), &getinitargs) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(__getinitargs__), &getinitargs) < 0) { return NULL; } if (getinitargs != NULL) { diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index 3e742e067e7db1..a8d68d68420d36 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -3530,7 +3530,7 @@ expat_start_doctype_handler(XMLParserObject *self, sysid_obj, NULL); Py_XDECREF(res); } - else if (_PyObject_LookupAttr((PyObject *)self, st->str_doctype, &res) > 0) { + else if (PyObject_GetOptionalAttr((PyObject *)self, st->str_doctype, &res) > 0) { (void)PyErr_WarnEx(PyExc_RuntimeWarning, "The doctype() method of XMLParser is ignored. " "Define doctype() method on the TreeBuilder target.", diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index e58e87926f6731..bfc3d2558c9e36 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1463,7 +1463,7 @@ buffered_repr(buffered *self) { PyObject *nameobj, *res; - if (_PyObject_LookupAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { + if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { if (!PyErr_ExceptionMatches(PyExc_ValueError)) { return NULL; } @@ -1630,7 +1630,7 @@ _bufferedreader_read_all(buffered *self) } _bufferedreader_reset_buf(self); - if (_PyObject_LookupAttr(self->raw, &_Py_ID(readall), &readall) < 0) { + if (PyObject_GetOptionalAttr(self->raw, &_Py_ID(readall), &readall) < 0) { goto cleanup; } if (readall) { diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 1a5b61301dec58..39709fd2931315 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1099,7 +1099,7 @@ fileio_repr(fileio *self) if (self->fd < 0) return PyUnicode_FromFormat("<_io.FileIO [closed]>"); - if (_PyObject_LookupAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { + if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { return NULL; } if (nameobj == NULL) { diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 729a708a3fc40e..e2e8ef46adf901 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -148,7 +148,7 @@ iobase_is_closed(PyObject *self) int ret; /* This gets the derived attribute, which is *not* __IOBase_closed in most cases! */ - ret = _PyObject_LookupAttr(self, &_Py_ID(__IOBase_closed), &res); + ret = PyObject_GetOptionalAttr(self, &_Py_ID(__IOBase_closed), &res); Py_XDECREF(res); return ret; } @@ -196,7 +196,7 @@ iobase_check_closed(PyObject *self) int closed; /* This gets the derived attribute, which is *not* __IOBase_closed in most cases! */ - closed = _PyObject_LookupAttr(self, &_Py_ID(closed), &res); + closed = PyObject_GetOptionalAttr(self, &_Py_ID(closed), &res); if (closed > 0) { closed = PyObject_IsTrue(res); Py_DECREF(res); @@ -303,7 +303,7 @@ iobase_finalize(PyObject *self) /* If `closed` doesn't exist or can't be evaluated as bool, then the object is probably in an unusable state, so ignore. */ - if (_PyObject_LookupAttr(self, &_Py_ID(closed), &res) <= 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(closed), &res) <= 0) { PyErr_Clear(); closed = -1; } @@ -571,7 +571,7 @@ _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit) PyObject *peek, *buffer, *result; Py_ssize_t old_size = -1; - if (_PyObject_LookupAttr(self, &_Py_ID(peek), &peek) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(peek), &peek) < 0) { return NULL; } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index f704875280da32..a5cf9fc397f5fe 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -946,7 +946,7 @@ _textiowrapper_set_encoder(textio *self, PyObject *codec_info, return -1; /* Get the normalized named of the codec */ - if (_PyObject_LookupAttr(codec_info, &_Py_ID(name), &res) < 0) { + if (PyObject_GetOptionalAttr(codec_info, &_Py_ID(name), &res) < 0) { return -1; } if (res != NULL && PyUnicode_Check(res)) { @@ -1202,7 +1202,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, Py_IS_TYPE(buffer, state->PyBufferedWriter_Type) || Py_IS_TYPE(buffer, state->PyBufferedRandom_Type)) { - if (_PyObject_LookupAttr(buffer, &_Py_ID(raw), &raw) < 0) + if (PyObject_GetOptionalAttr(buffer, &_Py_ID(raw), &raw) < 0) goto error; /* Cache the raw FileIO object to speed up 'closed' checks */ if (raw != NULL) { @@ -1222,7 +1222,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; self->seekable = self->telling = r; - r = _PyObject_LookupAttr(buffer, &_Py_ID(read1), &res); + r = PyObject_GetOptionalAttr(buffer, &_Py_ID(read1), &res); if (r < 0) { goto error; } @@ -2897,7 +2897,7 @@ textiowrapper_repr(textio *self) } goto error; } - if (_PyObject_LookupAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { + if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(name), &nameobj) < 0) { if (!PyErr_ExceptionMatches(PyExc_ValueError)) { goto error; } @@ -2913,7 +2913,7 @@ textiowrapper_repr(textio *self) if (res == NULL) goto error; } - if (_PyObject_LookupAttr((PyObject *) self, &_Py_ID(mode), &modeobj) < 0) { + if (PyObject_GetOptionalAttr((PyObject *) self, &_Py_ID(mode), &modeobj) < 0) { goto error; } if (modeobj != NULL) { @@ -3130,7 +3130,7 @@ textiowrapper_newlines_get(textio *self, void *context) PyObject *res; CHECK_ATTACHED(self); if (self->decoder == NULL || - _PyObject_LookupAttr(self->decoder, &_Py_ID(newlines), &res) == 0) + PyObject_GetOptionalAttr(self->decoder, &_Py_ID(newlines), &res) == 0) { Py_RETURN_NONE; } diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 5ecf7ca7cb9bc5..ea44b494cdd7cd 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -406,7 +406,7 @@ init_method_ref(PyObject *self, PyObject *name, /* *method_func and *method_self should be consistent. All refcount decrements should be occurred after setting *method_self and *method_func. */ - ret = _PyObject_LookupAttr(self, name, &func); + ret = PyObject_GetOptionalAttr(self, name, &func); if (func == NULL) { *method_self = NULL; Py_CLEAR(*method_func); @@ -1224,7 +1224,7 @@ static int _Pickler_SetOutputStream(PicklerObject *self, PyObject *file) { assert(file != NULL); - if (_PyObject_LookupAttr(file, &_Py_ID(write), &self->write) < 0) { + if (PyObject_GetOptionalAttr(file, &_Py_ID(write), &self->write) < 0) { return -1; } if (self->write == NULL) { @@ -1694,16 +1694,16 @@ static int _Unpickler_SetInputStream(UnpicklerObject *self, PyObject *file) { /* Optional file methods */ - if (_PyObject_LookupAttr(file, &_Py_ID(peek), &self->peek) < 0) { + if (PyObject_GetOptionalAttr(file, &_Py_ID(peek), &self->peek) < 0) { goto error; } - if (_PyObject_LookupAttr(file, &_Py_ID(readinto), &self->readinto) < 0) { + if (PyObject_GetOptionalAttr(file, &_Py_ID(readinto), &self->readinto) < 0) { goto error; } - if (_PyObject_LookupAttr(file, &_Py_ID(read), &self->read) < 0) { + if (PyObject_GetOptionalAttr(file, &_Py_ID(read), &self->read) < 0) { goto error; } - if (_PyObject_LookupAttr(file, &_Py_ID(readline), &self->readline) < 0) { + if (PyObject_GetOptionalAttr(file, &_Py_ID(readline), &self->readline) < 0) { goto error; } if (!self->readline || !self->read) { @@ -1900,7 +1900,7 @@ get_deep_attribute(PyObject *obj, PyObject *names, PyObject **pparent) for (i = 0; i < n; i++) { PyObject *name = PyList_GET_ITEM(names, i); Py_XSETREF(parent, obj); - (void)_PyObject_LookupAttr(parent, name, &obj); + (void)PyObject_GetOptionalAttr(parent, name, &obj); if (obj == NULL) { Py_DECREF(parent); return NULL; @@ -1927,7 +1927,7 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname) Py_DECREF(dotted_path); } else { - (void)_PyObject_LookupAttr(obj, name, &attr); + (void)PyObject_GetOptionalAttr(obj, name, &attr); } if (attr == NULL && !PyErr_Occurred()) { PyErr_Format(PyExc_AttributeError, @@ -1968,7 +1968,7 @@ whichmodule(PyObject *global, PyObject *dotted_path) Py_ssize_t i; PyObject *modules; - if (_PyObject_LookupAttr(global, &_Py_ID(__module__), &module_name) < 0) { + if (PyObject_GetOptionalAttr(global, &_Py_ID(__module__), &module_name) < 0) { return NULL; } if (module_name) { @@ -3656,7 +3656,7 @@ save_global(PickleState *st, PicklerObject *self, PyObject *obj, global_name = Py_NewRef(name); } else { - if (_PyObject_LookupAttr(obj, &_Py_ID(__qualname__), &global_name) < 0) + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__qualname__), &global_name) < 0) goto error; if (global_name == NULL) { global_name = PyObject_GetAttr(obj, &_Py_ID(__name__)); @@ -3979,7 +3979,7 @@ get_class(PyObject *obj) { PyObject *cls; - if (_PyObject_LookupAttr(obj, &_Py_ID(__class__), &cls) == 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__class__), &cls) == 0) { cls = Py_NewRef(Py_TYPE(obj)); } return cls; @@ -4062,7 +4062,7 @@ save_reduce(PickleState *st, PicklerObject *self, PyObject *args, if (self->proto >= 2) { PyObject *name; - if (_PyObject_LookupAttr(callable, &_Py_ID(__name__), &name) < 0) { + if (PyObject_GetOptionalAttr(callable, &_Py_ID(__name__), &name) < 0) { return -1; } if (name != NULL && PyUnicode_Check(name)) { @@ -4462,7 +4462,7 @@ save(PickleState *st, PicklerObject *self, PyObject *obj, int pers_save) don't actually have to check for a __reduce__ method. */ /* Check for a __reduce_ex__ method. */ - if (_PyObject_LookupAttr(obj, &_Py_ID(__reduce_ex__), &reduce_func) < 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__reduce_ex__), &reduce_func) < 0) { goto error; } if (reduce_func != NULL) { @@ -4474,7 +4474,7 @@ save(PickleState *st, PicklerObject *self, PyObject *obj, int pers_save) } else { /* Check for a __reduce__ method. */ - if (_PyObject_LookupAttr(obj, &_Py_ID(__reduce__), &reduce_func) < 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__reduce__), &reduce_func) < 0) { goto error; } if (reduce_func != NULL) { @@ -4526,7 +4526,7 @@ dump(PickleState *state, PicklerObject *self, PyObject *obj) int status = -1; PyObject *tmp; - if (_PyObject_LookupAttr((PyObject *)self, &_Py_ID(reducer_override), + if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(reducer_override), &tmp) < 0) { goto error; } @@ -4796,7 +4796,7 @@ _pickle_Pickler___init___impl(PicklerObject *self, PyObject *file, if (self->dispatch_table != NULL) { return 0; } - if (_PyObject_LookupAttr((PyObject *)self, &_Py_ID(dispatch_table), + if (PyObject_GetOptionalAttr((PyObject *)self, &_Py_ID(dispatch_table), &self->dispatch_table) < 0) { return -1; } @@ -5797,7 +5797,7 @@ instantiate(PyObject *cls, PyObject *args) assert(PyTuple_Check(args)); if (!PyTuple_GET_SIZE(args) && PyType_Check(cls)) { PyObject *func; - if (_PyObject_LookupAttr(cls, &_Py_ID(__getinitargs__), &func) < 0) { + if (PyObject_GetOptionalAttr(cls, &_Py_ID(__getinitargs__), &func) < 0) { return NULL; } if (func == NULL) { @@ -6451,7 +6451,7 @@ do_append(PickleState *state, UnpicklerObject *self, Py_ssize_t x) else { PyObject *extend_func; - if (_PyObject_LookupAttr(list, &_Py_ID(extend), &extend_func) < 0) { + if (PyObject_GetOptionalAttr(list, &_Py_ID(extend), &extend_func) < 0) { return -1; } if (extend_func != NULL) { @@ -6637,7 +6637,7 @@ load_build(PickleState *st, UnpicklerObject *self) inst = self->stack->data[Py_SIZE(self->stack) - 1]; - if (_PyObject_LookupAttr(inst, &_Py_ID(__setstate__), &setstate) < 0) { + if (PyObject_GetOptionalAttr(inst, &_Py_ID(__setstate__), &setstate) < 0) { Py_DECREF(state); return -1; } diff --git a/Modules/_sqlite/microprotocols.c b/Modules/_sqlite/microprotocols.c index 148220d0f91f96..92f0148bd4c217 100644 --- a/Modules/_sqlite/microprotocols.c +++ b/Modules/_sqlite/microprotocols.c @@ -98,7 +98,7 @@ pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj, } /* try to have the protocol adapt this object */ - if (_PyObject_LookupAttr(proto, state->str___adapt__, &adapter) < 0) { + if (PyObject_GetOptionalAttr(proto, state->str___adapt__, &adapter) < 0) { return NULL; } if (adapter) { @@ -117,7 +117,7 @@ pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj, } /* and finally try to have the object adapt itself */ - if (_PyObject_LookupAttr(obj, state->str___conform__, &adapter) < 0) { + if (PyObject_GetOptionalAttr(obj, state->str___conform__, &adapter) < 0) { return NULL; } if (adapter) { diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index f570b4e7007156..82393309b67039 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1438,7 +1438,7 @@ thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value, PyObject *name = NULL; if (thread != Py_None) { - if (_PyObject_LookupAttr(thread, &_Py_ID(name), &name) < 0) { + if (PyObject_GetOptionalAttr(thread, &_Py_ID(name), &name) < 0) { return -1; } } diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index f43a23467976b8..0000a8d637eb56 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2268,7 +2268,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, if (protocol == -1 && PyErr_Occurred()) return NULL; - if (_PyObject_LookupAttr((PyObject *)self, state->str___dict__, &dict) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)self, state->str___dict__, &dict) < 0) { return NULL; } if (dict == NULL) { diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 13ff253f560b04..f5f7bf33bf8f4b 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -1146,7 +1146,7 @@ itertools_tee_impl(PyObject *module, PyObject *iterable, Py_ssize_t n) return NULL; } - if (_PyObject_LookupAttr(it, &_Py_ID(__copy__), ©func) < 0) { + if (PyObject_GetOptionalAttr(it, &_Py_ID(__copy__), ©func) < 0) { Py_DECREF(it); Py_DECREF(result); return NULL; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 28915359fb49e2..5721ed4412be57 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -832,7 +832,7 @@ pyexpat_xmlparser_ParseFile_impl(xmlparseobject *self, PyTypeObject *cls, pyexpat_state *state = PyType_GetModuleState(cls); - if (_PyObject_LookupAttr(file, state->str_read, &readmethod) < 0) { + if (PyObject_GetOptionalAttr(file, state->str_read, &readmethod) < 0) { return NULL; } if (readmethod == NULL) { diff --git a/Objects/abstract.c b/Objects/abstract.c index e595bc91c220f6..b4edcec6007710 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -182,7 +182,7 @@ PyObject_GetItem(PyObject *o, PyObject *key) return Py_GenericAlias(o, key); } - if (_PyObject_LookupAttr(o, &_Py_ID(__class_getitem__), &meth) < 0) { + if (PyObject_GetOptionalAttr(o, &_Py_ID(__class_getitem__), &meth) < 0) { return NULL; } if (meth && meth != Py_None) { @@ -2552,7 +2552,7 @@ abstract_get_bases(PyObject *cls) { PyObject *bases; - (void)_PyObject_LookupAttr(cls, &_Py_ID(__bases__), &bases); + (void)PyObject_GetOptionalAttr(cls, &_Py_ID(__bases__), &bases); if (bases != NULL && !PyTuple_Check(bases)) { Py_DECREF(bases); return NULL; @@ -2636,7 +2636,7 @@ object_isinstance(PyObject *inst, PyObject *cls) if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); if (retval == 0) { - retval = _PyObject_LookupAttr(inst, &_Py_ID(__class__), &icls); + retval = PyObject_GetOptionalAttr(inst, &_Py_ID(__class__), &icls); if (icls != NULL) { if (icls != (PyObject *)(Py_TYPE(inst)) && PyType_Check(icls)) { retval = PyType_IsSubtype( @@ -2654,7 +2654,7 @@ object_isinstance(PyObject *inst, PyObject *cls) if (!check_class(cls, "isinstance() arg 2 must be a type, a tuple of types, or a union")) return -1; - retval = _PyObject_LookupAttr(inst, &_Py_ID(__class__), &icls); + retval = PyObject_GetOptionalAttr(inst, &_Py_ID(__class__), &icls); if (icls != NULL) { retval = abstract_issubclass(icls, cls); Py_DECREF(icls); diff --git a/Objects/call.c b/Objects/call.c index 5045c0dc92843b..396552d85cfca0 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -173,7 +173,7 @@ object_is_not_callable(PyThreadState *tstate, PyObject *callable) goto basic_type_error; } PyObject *attr; - int res = _PyObject_LookupAttr(callable, name, &attr); + int res = PyObject_GetOptionalAttr(callable, name, &attr); if (res < 0) { _PyErr_Clear(tstate); } diff --git a/Objects/classobject.c b/Objects/classobject.c index 71c4a4e5d0f8ab..548b8672f86321 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -275,9 +275,9 @@ method_repr(PyMethodObject *a) PyObject *funcname, *result; const char *defname = "?"; - if (_PyObject_LookupAttr(func, &_Py_ID(__qualname__), &funcname) < 0 || + if (PyObject_GetOptionalAttr(func, &_Py_ID(__qualname__), &funcname) < 0 || (funcname == NULL && - _PyObject_LookupAttr(func, &_Py_ID(__name__), &funcname) < 0)) + PyObject_GetOptionalAttr(func, &_Py_ID(__name__), &funcname) < 0)) { return NULL; } @@ -479,7 +479,7 @@ instancemethod_repr(PyObject *self) return NULL; } - if (_PyObject_LookupAttr(func, &_Py_ID(__name__), &funcname) < 0) { + if (PyObject_GetOptionalAttr(func, &_Py_ID(__name__), &funcname) < 0) { return NULL; } if (funcname != NULL && !PyUnicode_Check(funcname)) { diff --git a/Objects/descrobject.c b/Objects/descrobject.c index a81490285eed4a..810bd196e8f7e7 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1792,7 +1792,7 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, } /* if no docstring given and the getter has one, use that one */ else if (fget != NULL) { - int rc = _PyObject_LookupAttr(fget, &_Py_ID(__doc__), &prop_doc); + int rc = PyObject_GetOptionalAttr(fget, &_Py_ID(__doc__), &prop_doc); if (rc <= 0) { return rc; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 194081db2f290a..013c21884032aa 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2664,7 +2664,7 @@ dict_update_arg(PyObject *self, PyObject *arg) return PyDict_Merge(self, arg, 1); } PyObject *func; - if (_PyObject_LookupAttr(arg, &_Py_ID(keys), &func) < 0) { + if (PyObject_GetOptionalAttr(arg, &_Py_ID(keys), &func) < 0) { return -1; } if (func != NULL) { diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 85cf2cca16516b..42c5317d83d0c9 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -208,7 +208,7 @@ BaseException_add_note(PyObject *self, PyObject *note) } PyObject *notes; - if (_PyObject_LookupAttr(self, &_Py_ID(__notes__), ¬es) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(__notes__), ¬es) < 0) { return NULL; } if (notes == NULL) { @@ -941,7 +941,7 @@ exceptiongroup_subset( PyException_SetCause(eg, PyException_GetCause(orig)); PyObject *notes; - if (_PyObject_LookupAttr(orig, &_Py_ID(__notes__), ¬es) < 0) { + if (PyObject_GetOptionalAttr(orig, &_Py_ID(__notes__), ¬es) < 0) { goto error; } if (notes) { diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 6d980a1b379166..751fb69d0891cf 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -176,7 +176,7 @@ PyObject_AsFileDescriptor(PyObject *o) if (PyLong_Check(o)) { fd = _PyLong_AsInt(o); } - else if (_PyObject_LookupAttr(o, &_Py_ID(fileno), &meth) < 0) { + else if (PyObject_GetOptionalAttr(o, &_Py_ID(fileno), &meth) < 0) { return -1; } else if (meth != NULL) { diff --git a/Objects/funcobject.c b/Objects/funcobject.c index a8a9ee2b9bad46..0c69bf4ebcfed5 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -943,7 +943,7 @@ static int functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name) { PyObject *value; - int res = _PyObject_LookupAttr(wrapped, name, &value); + int res = PyObject_GetOptionalAttr(wrapped, name, &value); if (value != NULL) { res = PyObject_SetAttr(wrapper, name, value); Py_DECREF(value); diff --git a/Objects/genericaliasobject.c b/Objects/genericaliasobject.c index 117b4e8dfb960a..0c478f3717e036 100644 --- a/Objects/genericaliasobject.c +++ b/Objects/genericaliasobject.c @@ -63,12 +63,12 @@ ga_repr_item(_PyUnicodeWriter *writer, PyObject *p) goto done; } - if (_PyObject_LookupAttr(p, &_Py_ID(__origin__), &tmp) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__origin__), &tmp) < 0) { goto done; } if (tmp != NULL) { Py_DECREF(tmp); - if (_PyObject_LookupAttr(p, &_Py_ID(__args__), &tmp) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__args__), &tmp) < 0) { goto done; } if (tmp != NULL) { @@ -78,13 +78,13 @@ ga_repr_item(_PyUnicodeWriter *writer, PyObject *p) } } - if (_PyObject_LookupAttr(p, &_Py_ID(__qualname__), &qualname) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) { goto done; } if (qualname == NULL) { goto use_repr; } - if (_PyObject_LookupAttr(p, &_Py_ID(__module__), &module) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) { goto done; } if (module == NULL || module == Py_None) { @@ -257,7 +257,7 @@ _Py_make_parameters(PyObject *args) if (PyType_Check(t)) { continue; } - if (_PyObject_LookupAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) { + if (PyObject_GetOptionalAttr(t, &_Py_ID(__typing_subst__), &subst) < 0) { Py_DECREF(parameters); return NULL; } @@ -267,7 +267,7 @@ _Py_make_parameters(PyObject *args) } else { PyObject *subparams; - if (_PyObject_LookupAttr(t, &_Py_ID(__parameters__), + if (PyObject_GetOptionalAttr(t, &_Py_ID(__parameters__), &subparams) < 0) { Py_DECREF(parameters); return NULL; @@ -310,7 +310,7 @@ subs_tvars(PyObject *obj, PyObject *params, PyObject **argitems, Py_ssize_t nargs) { PyObject *subparams; - if (_PyObject_LookupAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__parameters__), &subparams) < 0) { return NULL; } if (subparams && PyTuple_Check(subparams) && PyTuple_GET_SIZE(subparams)) { @@ -361,7 +361,7 @@ _is_unpacked_typevartuple(PyObject *arg) if (PyType_Check(arg)) { // TODO: Add test return 0; } - int res = _PyObject_LookupAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp); + int res = PyObject_GetOptionalAttr(arg, &_Py_ID(__typing_is_unpacked_typevartuple__), &tmp); if (res > 0) { res = PyObject_IsTrue(tmp); Py_DECREF(tmp); @@ -383,7 +383,7 @@ _unpacked_tuple_args(PyObject *arg) return Py_NewRef(result); } - if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) { + if (PyObject_GetOptionalAttr(arg, &_Py_ID(__typing_unpacked_tuple_args__), &result) > 0) { if (result == Py_None) { Py_DECREF(result); return NULL; @@ -448,7 +448,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje for (Py_ssize_t i = 0; i < nparams; i++) { PyObject *param = PyTuple_GET_ITEM(parameters, i); PyObject *prepare, *tmp; - if (_PyObject_LookupAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) { + if (PyObject_GetOptionalAttr(param, &_Py_ID(__typing_prepare_subst__), &prepare) < 0) { Py_DECREF(item); return NULL; } @@ -503,7 +503,7 @@ _Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObje return NULL; } PyObject *subst; - if (_PyObject_LookupAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) { + if (PyObject_GetOptionalAttr(arg, &_Py_ID(__typing_subst__), &subst) < 0) { Py_DECREF(newargs); Py_DECREF(item); return NULL; diff --git a/Objects/genobject.c b/Objects/genobject.c index 6f0f02c9a16e5e..103e8b8bb882f6 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -317,7 +317,7 @@ gen_close_iter(PyObject *yf) } else { PyObject *meth; - if (_PyObject_LookupAttr(yf, &_Py_ID(close), &meth) < 0) { + if (PyObject_GetOptionalAttr(yf, &_Py_ID(close), &meth) < 0) { PyErr_WriteUnraisable(yf); } if (meth) { @@ -492,7 +492,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, } else { /* `yf` is an iterator or a coroutine-like object. */ PyObject *meth; - if (_PyObject_LookupAttr(yf, &_Py_ID(throw), &meth) < 0) { + if (PyObject_GetOptionalAttr(yf, &_Py_ID(throw), &meth) < 0) { Py_DECREF(yf); return NULL; } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 3e500b555e70ff..4071b5a3f1a62c 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -742,7 +742,7 @@ _PyModuleSpec_IsInitializing(PyObject *spec) { if (spec != NULL) { PyObject *value; - int ok = _PyObject_LookupAttr(spec, &_Py_ID(_initializing), &value); + int ok = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value); if (ok == 0) { return 0; } diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 39b0f684510578..e76d2ded61cf74 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -2154,7 +2154,7 @@ mutablemapping_update_arg(PyObject *self, PyObject *arg) return res; } PyObject *func; - if (_PyObject_LookupAttr(arg, &_Py_ID(keys), &func) < 0) { + if (PyObject_GetOptionalAttr(arg, &_Py_ID(keys), &func) < 0) { return -1; } if (func != NULL) { @@ -2186,7 +2186,7 @@ mutablemapping_update_arg(PyObject *self, PyObject *arg) } return 0; } - if (_PyObject_LookupAttr(arg, &_Py_ID(items), &func) < 0) { + if (PyObject_GetOptionalAttr(arg, &_Py_ID(items), &func) < 0) { return -1; } if (func != NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5430924e69dee3..b1f9f1280fd04d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2359,7 +2359,7 @@ static PyObject * class_name(PyObject *cls) { PyObject *name; - if (_PyObject_LookupAttr(cls, &_Py_ID(__name__), &name) == 0) { + if (PyObject_GetOptionalAttr(cls, &_Py_ID(__name__), &name) == 0) { name = PyObject_Repr(cls); } return name; @@ -3865,7 +3865,7 @@ type_new_get_bases(type_new_ctx *ctx, PyObject **type) continue; } PyObject *mro_entries; - if (_PyObject_LookupAttr(base, &_Py_ID(__mro_entries__), + if (PyObject_GetOptionalAttr(base, &_Py_ID(__mro_entries__), &mro_entries) < 0) { return -1; } @@ -5147,7 +5147,7 @@ merge_class_dict(PyObject *dict, PyObject *aclass) assert(aclass); /* Merge in the type's dict (if any). */ - if (_PyObject_LookupAttr(aclass, &_Py_ID(__dict__), &classdict) < 0) { + if (PyObject_GetOptionalAttr(aclass, &_Py_ID(__dict__), &classdict) < 0) { return -1; } if (classdict != NULL) { @@ -5158,7 +5158,7 @@ merge_class_dict(PyObject *dict, PyObject *aclass) } /* Recursively merge in the base types' (if any) dicts. */ - if (_PyObject_LookupAttr(aclass, &_Py_ID(__bases__), &bases) < 0) { + if (PyObject_GetOptionalAttr(aclass, &_Py_ID(__bases__), &bases) < 0) { return -1; } if (bases != NULL) { @@ -5984,7 +5984,7 @@ object_getstate_default(PyObject *obj, int required) PyObject *name, *value; name = Py_NewRef(PyList_GET_ITEM(slotnames, i)); - if (_PyObject_LookupAttr(obj, name, &value) < 0) { + if (PyObject_GetOptionalAttr(obj, name, &value) < 0) { Py_DECREF(name); goto error; } @@ -6381,7 +6381,7 @@ object___reduce_ex___impl(PyObject *self, int protocol) } } - if (_PyObject_LookupAttr(self, &_Py_ID(__reduce__), &reduce) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(__reduce__), &reduce) < 0) { return NULL; } if (reduce != NULL) { @@ -6500,7 +6500,7 @@ object___dir___impl(PyObject *self) PyObject *itsclass = NULL; /* Get __dict__ (which may or may not be a real dict...) */ - if (_PyObject_LookupAttr(self, &_Py_ID(__dict__), &dict) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(__dict__), &dict) < 0) { return NULL; } if (dict == NULL) { @@ -6520,7 +6520,7 @@ object___dir___impl(PyObject *self) goto error; /* Merge in attrs reachable from its class. */ - if (_PyObject_LookupAttr(self, &_Py_ID(__class__), &itsclass) < 0) { + if (PyObject_GetOptionalAttr(self, &_Py_ID(__class__), &itsclass) < 0) { goto error; } /* XXX(tomer): Perhaps fall back to Py_TYPE(obj) if no @@ -8393,7 +8393,7 @@ method_is_overloaded(PyObject *left, PyObject *right, PyObject *name) PyObject *a, *b; int ok; - if (_PyObject_LookupAttr((PyObject *)(Py_TYPE(right)), name, &b) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)(Py_TYPE(right)), name, &b) < 0) { return -1; } if (b == NULL) { @@ -8401,7 +8401,7 @@ method_is_overloaded(PyObject *left, PyObject *right, PyObject *name) return 0; } - if (_PyObject_LookupAttr((PyObject *)(Py_TYPE(left)), name, &a) < 0) { + if (PyObject_GetOptionalAttr((PyObject *)(Py_TYPE(left)), name, &a) < 0) { Py_DECREF(b); return -1; } @@ -10373,7 +10373,7 @@ supercheck(PyTypeObject *type, PyObject *obj) /* Try the slow way */ PyObject *class_attr; - if (_PyObject_LookupAttr(obj, &_Py_ID(__class__), &class_attr) < 0) { + if (PyObject_GetOptionalAttr(obj, &_Py_ID(__class__), &class_attr) < 0) { return NULL; } if (class_attr != NULL && diff --git a/Objects/unionobject.c b/Objects/unionobject.c index f509a161bb9564..269f46914f263d 100644 --- a/Objects/unionobject.c +++ b/Objects/unionobject.c @@ -194,13 +194,13 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p) return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4); } - if (_PyObject_LookupAttr(p, &_Py_ID(__origin__), &tmp) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__origin__), &tmp) < 0) { goto exit; } if (tmp) { Py_DECREF(tmp); - if (_PyObject_LookupAttr(p, &_Py_ID(__args__), &tmp) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__args__), &tmp) < 0) { goto exit; } if (tmp) { @@ -210,13 +210,13 @@ union_repr_item(_PyUnicodeWriter *writer, PyObject *p) } } - if (_PyObject_LookupAttr(p, &_Py_ID(__qualname__), &qualname) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__qualname__), &qualname) < 0) { goto exit; } if (qualname == NULL) { goto use_repr; } - if (_PyObject_LookupAttr(p, &_Py_ID(__module__), &module) < 0) { + if (PyObject_GetOptionalAttr(p, &_Py_ID(__module__), &module) < 0) { goto exit; } if (module == NULL || module == Py_None) { diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index d4763ea260a5a2..e9665dd808af39 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -629,7 +629,7 @@ def isSimpleType(self, field): def visitField(self, field, name, sum=None, prod=None, depth=0): ctype = get_c_type(field.type) - line = "if (_PyObject_LookupAttr(obj, state->%s, &tmp) < 0) {" + line = "if (PyObject_GetOptionalAttr(obj, state->%s, &tmp) < 0) {" self.emit(line % field.name, depth) self.emit("return 1;", depth+1) self.emit("}", depth) @@ -813,7 +813,7 @@ def visitModule(self, mod): Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; - if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { + if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { goto cleanup; } if (fields) { @@ -887,7 +887,7 @@ def visitModule(self, mod): } PyObject *dict; - if (_PyObject_LookupAttr(self, state->__dict__, &dict) < 0) { + if (PyObject_GetOptionalAttr(self, state->__dict__, &dict) < 0) { return NULL; } if (dict) { diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 5db9ade3af4547..55a1370fbd038b 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -839,7 +839,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) Py_ssize_t i, numfields = 0; int res = -1; PyObject *key, *value, *fields; - if (_PyObject_LookupAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { + if (PyObject_GetOptionalAttr((PyObject*)Py_TYPE(self), state->_fields, &fields) < 0) { goto cleanup; } if (fields) { @@ -913,7 +913,7 @@ ast_type_reduce(PyObject *self, PyObject *unused) } PyObject *dict; - if (_PyObject_LookupAttr(self, state->__dict__, &dict) < 0) { + if (PyObject_GetOptionalAttr(self, state->__dict__, &dict) < 0) { return NULL; } if (dict) { @@ -5750,7 +5750,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) asdl_stmt_seq* body; asdl_type_ignore_seq* type_ignores; - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -5788,7 +5788,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_ignores, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_ignores, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -5838,7 +5838,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) if (isinstance) { asdl_stmt_seq* body; - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -5888,7 +5888,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) if (isinstance) { expr_ty body; - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -5918,7 +5918,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) asdl_expr_seq* argtypes; expr_ty returns; - if (_PyObject_LookupAttr(obj, state->argtypes, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->argtypes, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -5956,7 +5956,7 @@ obj2ast_mod(struct ast_state *state, PyObject* obj, mod_ty* out, PyArena* arena) } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6001,7 +6001,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* *out = NULL; return 0; } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6018,7 +6018,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6035,7 +6035,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6052,7 +6052,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6083,7 +6083,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* string type_comment; asdl_type_param_seq* type_params; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6100,7 +6100,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6117,7 +6117,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6155,7 +6155,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6193,7 +6193,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6210,7 +6210,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6227,7 +6227,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6286,7 +6286,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* string type_comment; asdl_type_param_seq* type_params; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6303,7 +6303,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6320,7 +6320,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6358,7 +6358,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6396,7 +6396,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->returns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->returns, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6413,7 +6413,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6430,7 +6430,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6488,7 +6488,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_expr_seq* decorator_list; asdl_type_param_seq* type_params; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6505,7 +6505,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->bases, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->bases, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6543,7 +6543,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->keywords, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6581,7 +6581,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6619,7 +6619,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->decorator_list, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->decorator_list, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6657,7 +6657,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6709,7 +6709,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6739,7 +6739,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { asdl_expr_seq* targets; - if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->targets, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6792,7 +6792,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* expr_ty value; string type_comment; - if (_PyObject_LookupAttr(obj, state->targets, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->targets, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6830,7 +6830,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6847,7 +6847,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -6879,7 +6879,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_type_param_seq* type_params; expr_ty value; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6896,7 +6896,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_params, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_params, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6934,7 +6934,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6966,7 +6966,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* operator_ty op; expr_ty value; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -6983,7 +6983,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7000,7 +7000,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7033,7 +7033,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* expr_ty value; int simple; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7050,7 +7050,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->annotation, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7067,7 +7067,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7084,7 +7084,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->simple, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->simple, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7118,7 +7118,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* orelse; string type_comment; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7135,7 +7135,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7152,7 +7152,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7190,7 +7190,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7228,7 +7228,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7262,7 +7262,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* orelse; string type_comment; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7279,7 +7279,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7296,7 +7296,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7334,7 +7334,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7372,7 +7372,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7405,7 +7405,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* body; asdl_stmt_seq* orelse; - if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7422,7 +7422,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7460,7 +7460,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7513,7 +7513,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* body; asdl_stmt_seq* orelse; - if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7530,7 +7530,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7568,7 +7568,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7621,7 +7621,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* body; string type_comment; - if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->items, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7659,7 +7659,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7697,7 +7697,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7729,7 +7729,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* body; string type_comment; - if (_PyObject_LookupAttr(obj, state->items, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->items, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7767,7 +7767,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7805,7 +7805,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7836,7 +7836,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* expr_ty subject; asdl_match_case_seq* cases; - if (_PyObject_LookupAttr(obj, state->subject, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->subject, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7853,7 +7853,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->cases, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->cases, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7905,7 +7905,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* expr_ty exc; expr_ty cause; - if (_PyObject_LookupAttr(obj, state->exc, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->exc, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7922,7 +7922,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->cause, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->cause, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -7955,7 +7955,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* orelse; asdl_stmt_seq* finalbody; - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -7993,7 +7993,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->handlers, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8031,7 +8031,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8069,7 +8069,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->finalbody, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8123,7 +8123,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_stmt_seq* orelse; asdl_stmt_seq* finalbody; - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8161,7 +8161,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->handlers, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->handlers, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8199,7 +8199,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8237,7 +8237,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->finalbody, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->finalbody, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8289,7 +8289,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* expr_ty test; expr_ty msg; - if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8306,7 +8306,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->msg, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->msg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -8336,7 +8336,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { asdl_alias_seq* names; - if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8389,7 +8389,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* asdl_alias_seq* names; int level; - if (_PyObject_LookupAttr(obj, state->module, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->module, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -8406,7 +8406,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8444,7 +8444,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->level, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->level, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -8474,7 +8474,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { asdl_identifier_seq* names; - if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8525,7 +8525,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { asdl_identifier_seq* names; - if (_PyObject_LookupAttr(obj, state->names, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->names, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8576,7 +8576,7 @@ obj2ast_stmt(struct ast_state *state, PyObject* obj, stmt_ty* out, PyArena* if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8658,7 +8658,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* *out = NULL; return 0; } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8675,7 +8675,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8692,7 +8692,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -8709,7 +8709,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -8735,7 +8735,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* boolop_ty op; asdl_expr_seq* values; - if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8752,7 +8752,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8804,7 +8804,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty target; expr_ty value; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8821,7 +8821,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8853,7 +8853,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* operator_ty op; expr_ty right; - if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->left, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8870,7 +8870,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8887,7 +8887,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->right, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->right, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8918,7 +8918,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* unaryop_ty op; expr_ty operand; - if (_PyObject_LookupAttr(obj, state->op, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->op, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8935,7 +8935,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->operand, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->operand, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8966,7 +8966,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* arguments_ty args; expr_ty body; - if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -8983,7 +8983,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9015,7 +9015,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty body; expr_ty orelse; - if (_PyObject_LookupAttr(obj, state->test, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->test, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9032,7 +9032,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9049,7 +9049,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->orelse, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->orelse, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9080,7 +9080,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* asdl_expr_seq* keys; asdl_expr_seq* values; - if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->keys, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9118,7 +9118,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9169,7 +9169,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (isinstance) { asdl_expr_seq* elts; - if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9221,7 +9221,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty elt; asdl_comprehension_seq* generators; - if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9238,7 +9238,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9290,7 +9290,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty elt; asdl_comprehension_seq* generators; - if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9307,7 +9307,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9360,7 +9360,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty value; asdl_comprehension_seq* generators; - if (_PyObject_LookupAttr(obj, state->key, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->key, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9377,7 +9377,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9394,7 +9394,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9446,7 +9446,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty elt; asdl_comprehension_seq* generators; - if (_PyObject_LookupAttr(obj, state->elt, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elt, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9463,7 +9463,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->generators, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->generators, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9514,7 +9514,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9544,7 +9544,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -9574,7 +9574,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9606,7 +9606,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* asdl_int_seq* ops; asdl_expr_seq* comparators; - if (_PyObject_LookupAttr(obj, state->left, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->left, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9623,7 +9623,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ops, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ops, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9661,7 +9661,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->comparators, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->comparators, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9714,7 +9714,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* asdl_expr_seq* args; asdl_keyword_seq* keywords; - if (_PyObject_LookupAttr(obj, state->func, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->func, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9731,7 +9731,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9769,7 +9769,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->keywords, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->keywords, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9822,7 +9822,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* int conversion; expr_ty format_spec; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9839,7 +9839,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->conversion, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->conversion, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9856,7 +9856,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->format_spec, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->format_spec, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -9887,7 +9887,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (isinstance) { asdl_expr_seq* values; - if (_PyObject_LookupAttr(obj, state->values, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->values, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9939,7 +9939,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* constant value; string kind; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -9956,7 +9956,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kind, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kind, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -9988,7 +9988,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* identifier attr; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10005,7 +10005,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->attr, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->attr, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10022,7 +10022,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10054,7 +10054,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty slice; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10071,7 +10071,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->slice, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->slice, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10088,7 +10088,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10119,7 +10119,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty value; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10136,7 +10136,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10167,7 +10167,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* identifier id; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->id, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->id, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10184,7 +10184,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10215,7 +10215,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* asdl_expr_seq* elts; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10253,7 +10253,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10284,7 +10284,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* asdl_expr_seq* elts; expr_context_ty ctx; - if (_PyObject_LookupAttr(obj, state->elts, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->elts, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10322,7 +10322,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ctx, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ctx, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10354,7 +10354,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* expr_ty upper; expr_ty step; - if (_PyObject_LookupAttr(obj, state->lower, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lower, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10371,7 +10371,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->upper, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->upper, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10388,7 +10388,7 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->step, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->step, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10738,7 +10738,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* asdl_expr_seq* ifs; int is_async; - if (_PyObject_LookupAttr(obj, state->target, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->target, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10755,7 +10755,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->iter, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->iter, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10772,7 +10772,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->ifs, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->ifs, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10810,7 +10810,7 @@ obj2ast_comprehension(struct ast_state *state, PyObject* obj, comprehension_ty* } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->is_async, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->is_async, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10852,7 +10852,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* *out = NULL; return 0; } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10869,7 +10869,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -10886,7 +10886,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10903,7 +10903,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10930,7 +10930,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* identifier name; asdl_stmt_seq* body; - if (_PyObject_LookupAttr(obj, state->type, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10947,7 +10947,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -10964,7 +10964,7 @@ obj2ast_excepthandler(struct ast_state *state, PyObject* obj, excepthandler_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11027,7 +11027,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, arg_ty kwarg; asdl_expr_seq* defaults; - if (_PyObject_LookupAttr(obj, state->posonlyargs, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->posonlyargs, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11065,7 +11065,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->args, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->args, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11103,7 +11103,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->vararg, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->vararg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11120,7 +11120,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kwonlyargs, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kwonlyargs, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11158,7 +11158,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kw_defaults, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kw_defaults, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11196,7 +11196,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kwarg, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kwarg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11213,7 +11213,7 @@ obj2ast_arguments(struct ast_state *state, PyObject* obj, arguments_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->defaults, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->defaults, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11272,7 +11272,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) int end_lineno; int end_col_offset; - if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->arg, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11289,7 +11289,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->annotation, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->annotation, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11306,7 +11306,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->type_comment, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->type_comment, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11323,7 +11323,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11340,7 +11340,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11357,7 +11357,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11374,7 +11374,7 @@ obj2ast_arg(struct ast_state *state, PyObject* obj, arg_ty* out, PyArena* arena) if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11412,7 +11412,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, int end_lineno; int end_col_offset; - if (_PyObject_LookupAttr(obj, state->arg, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->arg, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11429,7 +11429,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11446,7 +11446,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11463,7 +11463,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11480,7 +11480,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11497,7 +11497,7 @@ obj2ast_keyword(struct ast_state *state, PyObject* obj, keyword_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11535,7 +11535,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* int end_lineno; int end_col_offset; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11552,7 +11552,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->asname, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->asname, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11569,7 +11569,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11586,7 +11586,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11603,7 +11603,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11620,7 +11620,7 @@ obj2ast_alias(struct ast_state *state, PyObject* obj, alias_ty* out, PyArena* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11654,7 +11654,7 @@ obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, expr_ty context_expr; expr_ty optional_vars; - if (_PyObject_LookupAttr(obj, state->context_expr, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->context_expr, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11671,7 +11671,7 @@ obj2ast_withitem(struct ast_state *state, PyObject* obj, withitem_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->optional_vars, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->optional_vars, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11705,7 +11705,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, expr_ty guard; asdl_stmt_seq* body; - if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->pattern, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11722,7 +11722,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->guard, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->guard, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -11739,7 +11739,7 @@ obj2ast_match_case(struct ast_state *state, PyObject* obj, match_case_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->body, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->body, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11802,7 +11802,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, *out = NULL; return 0; } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11819,7 +11819,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11836,7 +11836,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11853,7 +11853,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11878,7 +11878,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (isinstance) { expr_ty value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11908,7 +11908,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (isinstance) { constant value; - if (_PyObject_LookupAttr(obj, state->value, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11938,7 +11938,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (isinstance) { asdl_pattern_seq* patterns; - if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -11991,7 +11991,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, asdl_pattern_seq* patterns; identifier rest; - if (_PyObject_LookupAttr(obj, state->keys, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->keys, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12029,7 +12029,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12067,7 +12067,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->rest, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->rest, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -12100,7 +12100,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, asdl_identifier_seq* kwd_attrs; asdl_pattern_seq* kwd_patterns; - if (_PyObject_LookupAttr(obj, state->cls, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->cls, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12117,7 +12117,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12155,7 +12155,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kwd_attrs, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kwd_attrs, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12193,7 +12193,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, } Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->kwd_patterns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->kwd_patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12245,7 +12245,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (isinstance) { identifier name; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -12276,7 +12276,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, pattern_ty pattern; identifier name; - if (_PyObject_LookupAttr(obj, state->pattern, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->pattern, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -12293,7 +12293,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -12323,7 +12323,7 @@ obj2ast_pattern(struct ast_state *state, PyObject* obj, pattern_ty* out, if (isinstance) { asdl_pattern_seq* patterns; - if (_PyObject_LookupAttr(obj, state->patterns, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->patterns, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12395,7 +12395,7 @@ obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* int lineno; string tag; - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12412,7 +12412,7 @@ obj2ast_type_ignore(struct ast_state *state, PyObject* obj, type_ignore_ty* if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->tag, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->tag, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12457,7 +12457,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, *out = NULL; return 0; } - if (_PyObject_LookupAttr(obj, state->lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12474,7 +12474,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12491,7 +12491,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_lineno, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_lineno, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12508,7 +12508,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->end_col_offset, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->end_col_offset, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12534,7 +12534,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, identifier name; expr_ty bound; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12551,7 +12551,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (res != 0) goto failed; Py_CLEAR(tmp); } - if (_PyObject_LookupAttr(obj, state->bound, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->bound, &tmp) < 0) { return 1; } if (tmp == NULL || tmp == Py_None) { @@ -12581,7 +12581,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (isinstance) { identifier name; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { @@ -12611,7 +12611,7 @@ obj2ast_type_param(struct ast_state *state, PyObject* obj, type_param_ty* out, if (isinstance) { identifier name; - if (_PyObject_LookupAttr(obj, state->name, &tmp) < 0) { + if (PyObject_GetOptionalAttr(obj, state->name, &tmp) < 0) { return 1; } if (tmp == NULL) { diff --git a/Python/_warnings.c b/Python/_warnings.c index e0580f01d9361d..82e621243a0c15 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -223,7 +223,7 @@ get_warnings_attr(PyInterpreterState *interp, PyObject *attr, int try_import) return NULL; } - (void)_PyObject_LookupAttr(warnings_module, attr, &obj); + (void)PyObject_GetOptionalAttr(warnings_module, attr, &obj); Py_DECREF(warnings_module); return obj; } @@ -1069,7 +1069,7 @@ get_source_line(PyInterpreterState *interp, PyObject *module_globals, int lineno Py_INCREF(module_name); /* Make sure the loader implements the optional get_source() method. */ - (void)_PyObject_LookupAttr(loader, &_Py_ID(get_source), &get_source); + (void)PyObject_GetOptionalAttr(loader, &_Py_ID(get_source), &get_source); Py_DECREF(loader); if (!get_source) { Py_DECREF(module_name); diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 20a86fc6f583d3..7d77fd5c0c328e 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -34,7 +34,7 @@ update_bases(PyObject *bases, PyObject *const *args, Py_ssize_t nargs) } continue; } - if (_PyObject_LookupAttr(base, &_Py_ID(__mro_entries__), &meth) < 0) { + if (PyObject_GetOptionalAttr(base, &_Py_ID(__mro_entries__), &meth) < 0) { goto error; } if (!meth) { @@ -175,7 +175,7 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs, } /* else: meta is not a class, so we cannot do the metaclass calculation, so we will use the explicitly given object as it is */ - if (_PyObject_LookupAttr(meta, &_Py_ID(__prepare__), &prep) < 0) { + if (PyObject_GetOptionalAttr(meta, &_Py_ID(__prepare__), &prep) < 0) { ns = NULL; } else if (prep == NULL) { @@ -1160,7 +1160,7 @@ builtin_getattr_impl(PyObject *module, PyObject *object, PyObject *name, PyObject *result; if (default_value != NULL) { - if (_PyObject_LookupAttr(object, name, &result) == 0) { + if (PyObject_GetOptionalAttr(object, name, &result) == 0) { return Py_NewRef(default_value); } } @@ -1209,7 +1209,7 @@ builtin_hasattr_impl(PyObject *module, PyObject *obj, PyObject *name) { PyObject *v; - if (_PyObject_LookupAttr(obj, name, &v) < 0) { + if (PyObject_GetOptionalAttr(obj, name, &v) < 0) { return NULL; } if (v == NULL) { @@ -2465,7 +2465,7 @@ builtin_vars_impl(PyObject *module, PyObject *object) d = _PyEval_GetFrameLocals(); } else { - if (_PyObject_LookupAttr(object, &_Py_ID(__dict__), &d) == 0) { + if (PyObject_GetOptionalAttr(object, &_Py_ID(__dict__), &d) == 0) { PyErr_SetString(PyExc_TypeError, "vars() argument must have __dict__ attribute"); } diff --git a/Python/ceval.c b/Python/ceval.c index 57e478c1313f64..63150a9456bbc8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -419,7 +419,7 @@ match_class_attr(PyThreadState *tstate, PyObject *subject, PyObject *type, return NULL; } PyObject *attr; - (void)_PyObject_LookupAttr(subject, name, &attr); + (void)PyObject_GetOptionalAttr(subject, name, &attr); return attr; } @@ -454,7 +454,7 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type, // First, the positional subpatterns: if (nargs) { int match_self = 0; - if (_PyObject_LookupAttr(type, &_Py_ID(__match_args__), &match_args) < 0) { + if (PyObject_GetOptionalAttr(type, &_Py_ID(__match_args__), &match_args) < 0) { goto fail; } if (match_args) { @@ -2414,7 +2414,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) PyObject *x; PyObject *fullmodname, *pkgname, *pkgpath, *pkgname_or_unknown, *errmsg; - if (_PyObject_LookupAttr(v, name, &x) != 0) { + if (PyObject_GetOptionalAttr(v, name, &x) != 0) { return x; } /* Issue #17636: in case this failed because of a circular relative diff --git a/Python/codecs.c b/Python/codecs.c index f9f23005debb1f..4e47ff93a3691b 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -516,7 +516,7 @@ PyObject * _PyCodec_LookupTextEncoding(const char *encoding, * attribute. */ if (!PyTuple_CheckExact(codec)) { - if (_PyObject_LookupAttr(codec, &_Py_ID(_is_text_encoding), &attr) < 0) { + if (PyObject_GetOptionalAttr(codec, &_Py_ID(_is_text_encoding), &attr) < 0) { Py_DECREF(codec); return NULL; } diff --git a/Python/errors.c b/Python/errors.c index b1a9858d82f7d6..916958c9a0ab00 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1748,7 +1748,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, } } if ((PyObject *)Py_TYPE(exc) != PyExc_SyntaxError) { - if (_PyObject_LookupAttr(exc, &_Py_ID(msg), &tmp) < 0) { + if (PyObject_GetOptionalAttr(exc, &_Py_ID(msg), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { @@ -1767,7 +1767,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, } } - if (_PyObject_LookupAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { + if (PyObject_GetOptionalAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { diff --git a/Python/import.c b/Python/import.c index 7ce89cdf9a91a0..3e52a4e4eb1450 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2878,7 +2878,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, } else { PyObject *path; - if (_PyObject_LookupAttr(mod, &_Py_ID(__path__), &path) < 0) { + if (PyObject_GetOptionalAttr(mod, &_Py_ID(__path__), &path) < 0) { goto error; } if (path) { diff --git a/Python/intrinsics.c b/Python/intrinsics.c index 82f8cce7f92a71..037b74ca820fab 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -40,11 +40,11 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v) int skip_leading_underscores = 0; int pos, err; - if (_PyObject_LookupAttr(v, &_Py_ID(__all__), &all) < 0) { + if (PyObject_GetOptionalAttr(v, &_Py_ID(__all__), &all) < 0) { return -1; /* Unexpected error */ } if (all == NULL) { - if (_PyObject_LookupAttr(v, &_Py_ID(__dict__), &dict) < 0) { + if (PyObject_GetOptionalAttr(v, &_Py_ID(__dict__), &dict) < 0) { return -1; } if (dict == NULL) { diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 60bf66c8a6bf89..721c527745c44a 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -953,7 +953,7 @@ print_exception_file_and_line(struct exception_print_context *ctx, PyObject *f = ctx->file; PyObject *tmp; - int res = _PyObject_LookupAttr(*value_p, &_Py_ID(print_file_and_line), &tmp); + int res = PyObject_GetOptionalAttr(*value_p, &_Py_ID(print_file_and_line), &tmp); if (res <= 0) { if (res < 0) { PyErr_Clear(); @@ -1132,7 +1132,7 @@ print_exception_notes(struct exception_print_context *ctx, PyObject *value) } PyObject *notes; - int res = _PyObject_LookupAttr(value, &_Py_ID(__notes__), ¬es); + int res = PyObject_GetOptionalAttr(value, &_Py_ID(__notes__), ¬es); if (res <= 0) { return res; } diff --git a/Python/suggestions.c b/Python/suggestions.c index ad58393490efc2..47aeb08180f6b1 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -247,7 +247,7 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame) } PyObject *value; - res = _PyObject_LookupAttr(self, name, &value); + res = PyObject_GetOptionalAttr(self, name, &value); Py_DECREF(locals); if (res < 0) { goto error; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 0ac6edc5a16f88..fea3f61ee01762 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -257,7 +257,7 @@ sys_audit_tstate(PyThreadState *ts, const char *event, PyThreadState_EnterTracing(ts); while ((hook = PyIter_Next(hooks)) != NULL) { PyObject *o; - int canTrace = _PyObject_LookupAttr(hook, &_Py_ID(__cantrace__), &o); + int canTrace = PyObject_GetOptionalAttr(hook, &_Py_ID(__cantrace__), &o); if (o) { canTrace = PyObject_IsTrue(o); Py_DECREF(o); @@ -657,7 +657,7 @@ sys_displayhook_unencodable(PyObject *outf, PyObject *o) if (encoded == NULL) goto error; - if (_PyObject_LookupAttr(outf, &_Py_ID(buffer), &buffer) < 0) { + if (PyObject_GetOptionalAttr(outf, &_Py_ID(buffer), &buffer) < 0) { Py_DECREF(encoded); goto error; } From 42bc485a24f0f67751474bd1697e1beb4a783b9a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 12 Jul 2023 12:28:10 +0200 Subject: [PATCH 366/446] gh-105373: Elaborate Pending Removal in What's New in Python 3.13 (#106675) Co-authored-by: Hugo van Kemenade --- Doc/whatsnew/3.13.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index dc020682ac1edd..b7c436fc151611 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -270,7 +270,9 @@ Pending Removal in Python 3.14 * :mod:`typing`: :class:`~typing.ByteString`, deprecated since Python 3.9, now causes a :exc:`DeprecationWarning` to be emitted when it is used. -* :class:`!urllib.parse.Quoter`. +* :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a + public API. + (Contributed by Gregory P. Smith in :gh:`88168`.) * :mod:`xml.etree.ElementTree`: Testing the truth value of an :class:`~xml.etree.ElementTree.Element` is deprecated and will raise an @@ -397,7 +399,12 @@ although there is currently no date scheduled for their removal. * :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is deprecated, use an exception instance. -* :mod:`re`: bad character in group name. +* :mod:`re`: More strict rules are now applied for numerical group references + and group names in regular expressions. Only sequence of ASCII digits is now + accepted as a numerical reference. The group name in bytes patterns and + replacement strings can now only contain ASCII letters and digits and + underscore. + (Contributed by Serhiy Storchaka in :gh:`91760`.) * :mod:`ssl` options and protocols: From 2ca008e2b738b8c08b4bf46b2b23f315d6510d92 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 12 Jul 2023 11:30:25 +0100 Subject: [PATCH 367/446] gh-105481: move Python/opcode_metadata.h to Include/internal/pycore_opcode_metadata.h (#106673) --- .gitattributes | 2 +- .../internal/pycore_opcode_metadata.h | 0 Makefile.pre.in | 12 ++++++------ Python/assemble.c | 8 ++++---- Python/ceval.c | 2 +- Python/compile.c | 2 +- Python/flowgraph.c | 2 +- Python/optimizer.c | 2 +- Tools/cases_generator/generate_cases.py | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) rename Python/opcode_metadata.h => Include/internal/pycore_opcode_metadata.h (100%) diff --git a/.gitattributes b/.gitattributes index 5e4ce963b63e5c..2616da74b48c0f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,7 +87,7 @@ Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/executor_cases.c.h generated Python/generated_cases.c.h generated -Python/opcode_metadata.h generated +Include/internal/pycore_opcode_metadata.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Python/opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h similarity index 100% rename from Python/opcode_metadata.h rename to Include/internal/pycore_opcode_metadata.h diff --git a/Makefile.pre.in b/Makefile.pre.in index 073b4bcc271ffc..a1ceedbd4812c0 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1548,30 +1548,30 @@ regen-cases: $(srcdir)/Tools/cases_generator/generate_cases.py \ --emit-line-directives \ -o $(srcdir)/Python/generated_cases.c.h.new \ - -m $(srcdir)/Python/opcode_metadata.h.new \ + -m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \ -e $(srcdir)/Python/executor_cases.c.h.new \ -p $(srcdir)/Lib/_opcode_metadata.py.new \ $(srcdir)/Python/bytecodes.c $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new - $(UPDATE_FILE) $(srcdir)/Python/opcode_metadata.h $(srcdir)/Python/opcode_metadata.h.new + $(UPDATE_FILE) $(srcdir)/Include/internal/pycore_opcode_metadata.h $(srcdir)/Include/internal/pycore_opcode_metadata.h.new $(UPDATE_FILE) $(srcdir)/Python/executor_cases.c.h $(srcdir)/Python/executor_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Lib/_opcode_metadata.py $(srcdir)/Lib/_opcode_metadata.py.new -Python/compile.o: $(srcdir)/Python/opcode_metadata.h +Python/compile.o: $(srcdir)/Include/internal/pycore_opcode_metadata.h Python/ceval.o: \ $(srcdir)/Python/ceval_macros.h \ $(srcdir)/Python/condvar.h \ $(srcdir)/Python/generated_cases.c.h \ - $(srcdir)/Python/opcode_metadata.h \ + $(srcdir)/Include/internal/pycore_opcode_metadata.h \ $(srcdir)/Python/opcode_targets.h Python/flowgraph.o: \ - $(srcdir)/Python/opcode_metadata.h + $(srcdir)/Include/internal/pycore_opcode_metadata.h Python/optimizer.o: \ $(srcdir)/Python/executor_cases.c.h \ - $(srcdir)/Python/opcode_metadata.h + $(srcdir)/Include/internal/pycore_opcode_metadata.h Python/frozen.o: $(FROZEN_FILES_OUT) diff --git a/Python/assemble.c b/Python/assemble.c index ff7bca22286cd7..b7012534d6cc4e 100644 --- a/Python/assemble.c +++ b/Python/assemble.c @@ -1,11 +1,11 @@ #include #include "Python.h" -#include "pycore_code.h" // write_location_entry_start() +#include "pycore_code.h" // write_location_entry_start() #include "pycore_compile.h" -#include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros -#include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE -#include "opcode_metadata.h" // IS_PSEUDO_INSTR +#include "pycore_opcode.h" // _PyOpcode_Caches[] and opcode category macros +#include "pycore_opcode_utils.h" // IS_BACKWARDS_JUMP_OPCODE +#include "pycore_opcode_metadata.h" // IS_PSEUDO_INSTR #define DEFAULT_CODE_SIZE 128 diff --git a/Python/ceval.c b/Python/ceval.c index 63150a9456bbc8..de44085d732cfa 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -14,6 +14,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES +#include "pycore_opcode_metadata.h" #include "pycore_opcode_utils.h" // MAKE_FUNCTION_* #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyInterpreterState_GET() @@ -30,7 +31,6 @@ #include "pycore_frame.h" #include "frameobject.h" // _PyInterpreterFrame_GetLine #include "opcode.h" -#include "opcode_metadata.h" #include "pydtrace.h" #include "setobject.h" #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX diff --git a/Python/compile.c b/Python/compile.c index 29ea2742fad0cf..d9e38cfdefaf23 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -36,7 +36,7 @@ #include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() -#include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 diff --git a/Python/flowgraph.c b/Python/flowgraph.c index e159a4356dfe46..04f269c5853835 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -8,7 +8,7 @@ #include "pycore_opcode_utils.h" #define NEED_OPCODE_METADATA -#include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed #undef NEED_OPCODE_METADATA diff --git a/Python/optimizer.c b/Python/optimizer.c index 7fc40e66057d30..c3fdee63a7ed48 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -2,7 +2,7 @@ #include "opcode.h" #include "pycore_interp.h" #include "pycore_opcode.h" -#include "opcode_metadata.h" +#include "pycore_opcode_metadata.h" #include "pycore_opcode_utils.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_uops.h" diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 8c77c1f08335df..a20abcde85b7c7 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -24,7 +24,7 @@ DEFAULT_INPUT = os.path.relpath(os.path.join(ROOT, "Python/bytecodes.c")) DEFAULT_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases.c.h")) DEFAULT_METADATA_OUTPUT = os.path.relpath( - os.path.join(ROOT, "Python/opcode_metadata.h") + os.path.join(ROOT, "Include/internal/pycore_opcode_metadata.h") ) DEFAULT_PYMETADATA_OUTPUT = os.path.relpath( os.path.join(ROOT, "Lib/_opcode_metadata.py") From e2d7366fb3df44e7434132636d49f22d6d25cc9f Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 12 Jul 2023 13:46:30 +0100 Subject: [PATCH 368/446] gh-99079: Update Windows build to use OpenSSL 3.0.9 (GH-106649) --- .../Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst | 1 + PCbuild/get_externals.bat | 4 ++-- PCbuild/openssl.props | 4 ++-- PCbuild/python.props | 4 ++-- PCbuild/readme.txt | 2 +- PCbuild/regen.targets | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst diff --git a/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst b/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst new file mode 100644 index 00000000000000..11f411be0f17c5 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-07-11-20-48-17.gh-issue-99079.CIMftz.rst @@ -0,0 +1 @@ +Update Windows build to use OpenSSL 3.0.9 diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 3a6f616f279220..257b360ba3506f 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.4.4 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1u +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-3.0.9 set libraries=%libraries% sqlite-3.42.0.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.13.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.13.0 @@ -76,7 +76,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1u +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.9 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.13.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/openssl.props b/PCbuild/openssl.props index 7071bb57c06cd7..5fd708b211e42d 100644 --- a/PCbuild/openssl.props +++ b/PCbuild/openssl.props @@ -10,10 +10,10 @@ - <_DLLSuffix>-1_1 + <_DLLSuffix>-3 <_DLLSuffix Condition="$(Platform) == 'ARM'">$(_DLLSuffix)-arm <_DLLSuffix Condition="$(Platform) == 'ARM64'">$(_DLLSuffix)-arm64 - $(_DLLSuffix) + $(_DLLSuffix) <_SSLDLL Include="$(opensslOutDir)\libcrypto$(_DLLSuffix).dll" /> diff --git a/PCbuild/python.props b/PCbuild/python.props index 68052ef668aa6c..d3586235c82652 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -74,8 +74,8 @@ $(ExternalsDir)libffi-3.4.4\ $(libffiDir)$(ArchName)\ $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1u\ - $(ExternalsDir)openssl-bin-1.1.1u\$(ArchName)\ + $(ExternalsDir)openssl-3.0.9\ + $(ExternalsDir)openssl-bin-3.0.9\$(ArchName)\ $(opensslOutDir)include $(ExternalsDir)\nasm-2.11.06\ $(ExternalsDir)\zlib-1.2.13\ diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 88b04a749e3b28..f0de142f0573b9 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -168,7 +168,7 @@ _lzma Homepage: https://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1u of the OpenSSL secure sockets + Python wrapper for version 3.0 of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/PCbuild/regen.targets b/PCbuild/regen.targets index e9e16a15f94cce..2dd786e5e82e36 100644 --- a/PCbuild/regen.targets +++ b/PCbuild/regen.targets @@ -104,8 +104,9 @@ <_LicenseSources Include="$(PySourcePath)LICENSE; $(PySourcePath)PC\crtlicense.txt; $(bz2Dir)LICENSE; - $(opensslOutDir)LICENSE; $(libffiDir)LICENSE;" /> + <_LicenseSources Include="$(opensslOutDir)LICENSE.txt" Condition="Exists('$(opensslOutDir)LICENSE.txt')" /> + <_LicenseSources Include="$(opensslOutDir)LICENSE" Condition="!Exists('$(opensslOutDir)LICENSE.txt')" /> <_LicenseSources Include="$(tcltkDir)tcllicense.terms; $(tcltkDir)tklicense.terms" Condition="$(IncludeTkinter)" /> From b03755a2347325a89a48b08fc158419000513bcb Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 12 Jul 2023 14:34:14 +0100 Subject: [PATCH 369/446] GH-104909: Break LOAD_GLOBAL specializations in micro-ops. (GH-106677) --- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_opcode_metadata.h | 10 +- ...-07-12-10-48-08.gh-issue-104909.sWjcr2.rst | 1 + Python/bytecodes.c | 39 +- Python/executor_cases.c.h | 314 ++++---- Python/generated_cases.c.h | 722 +++++++++--------- 6 files changed, 586 insertions(+), 502 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-12-10-48-08.gh-issue-104909.sWjcr2.rst diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index d1829eb3245d26..b6b1aeca6e5c5f 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -19,9 +19,9 @@ extern "C" { typedef struct { uint16_t counter; - uint16_t index; uint16_t module_keys_version; uint16_t builtin_keys_version; + uint16_t index; } _PyLoadGlobalCache; #define INLINE_CACHE_ENTRIES_LOAD_GLOBAL CACHE_ENTRIES(_PyLoadGlobalCache) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 4a41cd86a4287b..317f42afea8049 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -36,7 +36,10 @@ #define _BINARY_OP_ADD_UNICODE 314 #define _LOAD_LOCALS 315 #define _LOAD_FROM_DICT_OR_GLOBALS 316 -#define IS_NONE 317 +#define _SKIP_CACHE 317 +#define _GUARD_GLOBALS_VERSION 318 +#define _GUARD_BUILTINS_VERSION 319 +#define IS_NONE 320 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1312,6 +1315,9 @@ const char * const _PyOpcode_uop_name[512] = { [314] = "_BINARY_OP_ADD_UNICODE", [315] = "_LOAD_LOCALS", [316] = "_LOAD_FROM_DICT_OR_GLOBALS", - [317] = "IS_NONE", + [317] = "_SKIP_CACHE", + [318] = "_GUARD_GLOBALS_VERSION", + [319] = "_GUARD_BUILTINS_VERSION", + [320] = "IS_NONE", }; #endif // NEED_OPCODE_METADATA diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-12-10-48-08.gh-issue-104909.sWjcr2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-12-10-48-08.gh-issue-104909.sWjcr2.rst new file mode 100644 index 00000000000000..f20226e5c54d16 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-12-10-48-08.gh-issue-104909.sWjcr2.rst @@ -0,0 +1 @@ +Split :opcode:`LOAD_GLOBAL` specializations into micro-ops. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2f6b8c5ae2f9cb..f5ce2e72d26762 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1351,11 +1351,25 @@ dummy_func( null = NULL; } - inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/1, unused/1 -- null if (oparg & 1), res)) { - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); + op(_SKIP_CACHE, (unused/1 -- )) { + } + + op(_GUARD_GLOBALS_VERSION, (version/1 --)) { PyDictObject *dict = (PyDictObject *)GLOBALS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + } + + op(_GUARD_BUILTINS_VERSION, (version/1 --)) { + PyDictObject *dict = (PyDictObject *)BUILTINS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); + } + + op(_LOAD_GLOBAL_MODULE, (index/1 -- null if (oparg & 1), res)) { + PyDictObject *dict = (PyDictObject *)GLOBALS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); @@ -1364,15 +1378,8 @@ dummy_func( null = NULL; } - inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/1, bltn_version/1 -- null if (oparg & 1), res)) { - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); - DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); - PyDictObject *mdict = (PyDictObject *)GLOBALS(); + op(_LOAD_GLOBAL_BUILTINS, (index/1 -- null if (oparg & 1), res)) { PyDictObject *bdict = (PyDictObject *)BUILTINS(); - assert(opcode == LOAD_GLOBAL_BUILTIN); - DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); - DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(bdict->ma_keys)); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); res = entries[index].me_value; DEOPT_IF(res == NULL, LOAD_GLOBAL); @@ -1381,6 +1388,18 @@ dummy_func( null = NULL; } + macro(LOAD_GLOBAL_MODULE) = + _SKIP_CACHE + // Skip over the counter + _GUARD_GLOBALS_VERSION + + _SKIP_CACHE + // Skip over the builtins version + _LOAD_GLOBAL_MODULE; + + macro(LOAD_GLOBAL_BUILTIN) = + _SKIP_CACHE + // Skip over the counter + _GUARD_GLOBALS_VERSION + + _GUARD_BUILTINS_VERSION + + _LOAD_GLOBAL_BUILTINS; + inst(DELETE_FAST, (--)) { PyObject *v = GETLOCAL(oparg); ERROR_IF(v == NULL, unbound_local_error); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 681efb97d89a5f..94536ed8ce5a10 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1154,17 +1154,43 @@ break; } + case _SKIP_CACHE: { + break; + } + + case _GUARD_GLOBALS_VERSION: { + uint16_t version = (uint16_t)operand; + #line 1358 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)GLOBALS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + #line 1169 "Python/executor_cases.c.h" + break; + } + + case _GUARD_BUILTINS_VERSION: { + uint16_t version = (uint16_t)operand; + #line 1365 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)BUILTINS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + #line 1180 "Python/executor_cases.c.h" + break; + } + case DELETE_FAST: { - #line 1385 "Python/bytecodes.c" + #line 1404 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1163 "Python/executor_cases.c.h" + #line 1189 "Python/executor_cases.c.h" break; } case DELETE_DEREF: { - #line 1402 "Python/bytecodes.c" + #line 1421 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1175,14 +1201,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1179 "Python/executor_cases.c.h" + #line 1205 "Python/executor_cases.c.h" break; } case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1415 "Python/bytecodes.c" + #line 1434 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -1201,14 +1227,14 @@ } Py_INCREF(value); } - #line 1205 "Python/executor_cases.c.h" + #line 1231 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } case LOAD_DEREF: { PyObject *value; - #line 1436 "Python/bytecodes.c" + #line 1455 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1216,7 +1242,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1220 "Python/executor_cases.c.h" + #line 1246 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1224,18 +1250,18 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1446 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1233 "Python/executor_cases.c.h" + #line 1259 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case COPY_FREE_VARS: { - #line 1453 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1246,22 +1272,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1250 "Python/executor_cases.c.h" + #line 1276 "Python/executor_cases.c.h" break; } case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1466 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1259 "Python/executor_cases.c.h" + #line 1285 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1468 "Python/bytecodes.c" + #line 1487 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1265 "Python/executor_cases.c.h" + #line 1291 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1271,10 +1297,10 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1472 "Python/bytecodes.c" + #line 1491 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1278 "Python/executor_cases.c.h" + #line 1304 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1284,10 +1310,10 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1477 "Python/bytecodes.c" + #line 1496 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1291 "Python/executor_cases.c.h" + #line 1317 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1297,7 +1323,7 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1482 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1308,13 +1334,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1312 "Python/executor_cases.c.h" + #line 1338 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1493 "Python/bytecodes.c" + #line 1512 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1318 "Python/executor_cases.c.h" + #line 1344 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1323,13 +1349,13 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1500 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1329 "Python/executor_cases.c.h" + #line 1355 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1502 "Python/bytecodes.c" + #line 1521 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1333 "Python/executor_cases.c.h" + #line 1359 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1337,7 +1363,7 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1506 "Python/bytecodes.c" + #line 1525 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1352,7 +1378,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1356 "Python/executor_cases.c.h" + #line 1382 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1362,7 +1388,7 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1523 "Python/bytecodes.c" + #line 1542 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1370,13 +1396,13 @@ if (map == NULL) goto error; - #line 1374 "Python/executor_cases.c.h" + #line 1400 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1531 "Python/bytecodes.c" + #line 1550 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1380 "Python/executor_cases.c.h" + #line 1406 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1384,7 +1410,7 @@ } case SETUP_ANNOTATIONS: { - #line 1535 "Python/bytecodes.c" + #line 1554 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1422,7 +1448,7 @@ Py_DECREF(ann_dict); } } - #line 1426 "Python/executor_cases.c.h" + #line 1452 "Python/executor_cases.c.h" break; } @@ -1430,7 +1456,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1575 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1440,14 +1466,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1444 "Python/executor_cases.c.h" + #line 1470 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1585 "Python/bytecodes.c" + #line 1604 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1451 "Python/executor_cases.c.h" + #line 1477 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1455,7 +1481,7 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1589 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1463,12 +1489,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1467 "Python/executor_cases.c.h" + #line 1493 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1597 "Python/bytecodes.c" + #line 1616 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1472 "Python/executor_cases.c.h" + #line 1498 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1476,17 +1502,17 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1603 "Python/bytecodes.c" + #line 1622 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1485 "Python/executor_cases.c.h" + #line 1511 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1608 "Python/bytecodes.c" + #line 1627 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1490 "Python/executor_cases.c.h" + #line 1516 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1495,13 +1521,13 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1614 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1505 "Python/executor_cases.c.h" + #line 1531 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1512,20 +1538,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1697 "Python/bytecodes.c" + #line 1716 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1523 "Python/executor_cases.c.h" + #line 1549 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1704 "Python/bytecodes.c" + #line 1723 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1529 "Python/executor_cases.c.h" + #line 1555 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1539,7 +1565,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1708 "Python/bytecodes.c" + #line 1727 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1562,7 +1588,7 @@ res = res2; res2 = NULL; } - #line 1566 "Python/executor_cases.c.h" + #line 1592 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1574,7 +1600,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1749 "Python/bytecodes.c" + #line 1768 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1608,9 +1634,9 @@ NULL | meth | arg1 | ... | argN */ - #line 1612 "Python/executor_cases.c.h" + #line 1638 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1783 "Python/bytecodes.c" + #line 1802 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1619,12 +1645,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 1623 "Python/executor_cases.c.h" + #line 1649 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1792 "Python/bytecodes.c" + #line 1811 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 1628 "Python/executor_cases.c.h" + #line 1654 "Python/executor_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -1636,7 +1662,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2025 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1649,10 +1675,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 1653 "Python/executor_cases.c.h" + #line 1679 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2038 "Python/bytecodes.c" + #line 2057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -1660,7 +1686,7 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 1664 "Python/executor_cases.c.h" + #line 1690 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1670,7 +1696,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2048 "Python/bytecodes.c" + #line 2067 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1682,7 +1708,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1686 "Python/executor_cases.c.h" + #line 1712 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1692,7 +1718,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2063 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1708,7 +1734,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1712 "Python/executor_cases.c.h" + #line 1738 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1718,7 +1744,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2082 "Python/bytecodes.c" + #line 2101 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1731,7 +1757,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1735 "Python/executor_cases.c.h" + #line 1761 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1741,14 +1767,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2097 "Python/bytecodes.c" + #line 2116 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1747 "Python/executor_cases.c.h" + #line 1773 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2099 "Python/bytecodes.c" + #line 2118 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1752 "Python/executor_cases.c.h" + #line 1778 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1758,15 +1784,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2103 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1764 "Python/executor_cases.c.h" + #line 1790 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2105 "Python/bytecodes.c" + #line 2124 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1770 "Python/executor_cases.c.h" + #line 1796 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1777,12 +1803,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2110 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1783 "Python/executor_cases.c.h" + #line 1809 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2112 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1790,10 +1816,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1794 "Python/executor_cases.c.h" + #line 1820 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2120 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1802,7 +1828,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1806 "Python/executor_cases.c.h" + #line 1832 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1812,21 +1838,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2131 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1819 "Python/executor_cases.c.h" + #line 1845 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2134 "Python/bytecodes.c" + #line 2153 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1826 "Python/executor_cases.c.h" + #line 1852 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2139 "Python/bytecodes.c" + #line 2158 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1830 "Python/executor_cases.c.h" + #line 1856 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1834,17 +1860,17 @@ case IS_NONE: { PyObject *value = stack_pointer[-1]; PyObject *b; - #line 2218 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 1844 "Python/executor_cases.c.h" + #line 1870 "Python/executor_cases.c.h" Py_DECREF(value); - #line 2224 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" } - #line 1848 "Python/executor_cases.c.h" + #line 1874 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1852,13 +1878,13 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2241 "Python/bytecodes.c" + #line 2260 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1862 "Python/executor_cases.c.h" + #line 1888 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1869,16 +1895,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2249 "Python/bytecodes.c" + #line 2268 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1878 "Python/executor_cases.c.h" + #line 1904 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2254 "Python/bytecodes.c" + #line 2273 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1886,7 +1912,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1890 "Python/executor_cases.c.h" + #line 1916 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1895,10 +1921,10 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2264 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1902 "Python/executor_cases.c.h" + #line 1928 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1907,10 +1933,10 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2269 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1914 "Python/executor_cases.c.h" + #line 1940 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1920,11 +1946,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2274 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1928 "Python/executor_cases.c.h" + #line 1954 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1933,14 +1959,14 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2280 "Python/bytecodes.c" + #line 2299 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1940 "Python/executor_cases.c.h" + #line 1966 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2283 "Python/bytecodes.c" + #line 2302 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1944 "Python/executor_cases.c.h" + #line 1970 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1948,7 +1974,7 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2287 "Python/bytecodes.c" + #line 2306 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1971,11 +1997,11 @@ if (iter == NULL) { goto error; } - #line 1975 "Python/executor_cases.c.h" + #line 2001 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2310 "Python/bytecodes.c" + #line 2329 "Python/bytecodes.c" } - #line 1979 "Python/executor_cases.c.h" + #line 2005 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1985,7 +2011,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2542 "Python/bytecodes.c" + #line 2561 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2006,7 +2032,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 2010 "Python/executor_cases.c.h" + #line 2036 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -2015,7 +2041,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2581 "Python/bytecodes.c" + #line 2600 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2025,7 +2051,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 2029 "Python/executor_cases.c.h" + #line 2055 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2034,7 +2060,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 2980 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2042,7 +2068,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 2046 "Python/executor_cases.c.h" + #line 2072 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -2050,7 +2076,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3394 "Python/bytecodes.c" + #line 3413 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2062,7 +2088,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 2066 "Python/executor_cases.c.h" + #line 2092 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -2070,7 +2096,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3408 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2095,7 +2121,7 @@ default: Py_UNREACHABLE(); } - #line 2099 "Python/executor_cases.c.h" + #line 2125 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -2106,15 +2132,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3458 "Python/bytecodes.c" + #line 3477 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 2112 "Python/executor_cases.c.h" + #line 2138 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3460 "Python/bytecodes.c" + #line 3479 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 2118 "Python/executor_cases.c.h" + #line 2144 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -2124,14 +2150,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3464 "Python/bytecodes.c" + #line 3483 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 2135 "Python/executor_cases.c.h" + #line 2161 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -2139,7 +2165,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3473 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2150,7 +2176,7 @@ else { res = value; } - #line 2154 "Python/executor_cases.c.h" + #line 2180 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -2159,12 +2185,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3486 "Python/bytecodes.c" + #line 3505 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 2168 "Python/executor_cases.c.h" + #line 2194 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2173,10 +2199,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3493 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 2180 "Python/executor_cases.c.h" + #line 2206 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -2187,7 +2213,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3498 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2202,12 +2228,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 2206 "Python/executor_cases.c.h" + #line 2232 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3513 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2211 "Python/executor_cases.c.h" + #line 2237 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2216,9 +2242,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3518 "Python/bytecodes.c" + #line 3537 "Python/bytecodes.c" assert(oparg >= 2); - #line 2222 "Python/executor_cases.c.h" + #line 2248 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index eb3de5e5bca97f..fcdf732315830a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1896,71 +1896,103 @@ } TARGET(LOAD_GLOBAL_MODULE) { - PyObject *null = NULL; - PyObject *res; - uint16_t index = read_u16(&next_instr[1].cache); - uint16_t version = read_u16(&next_instr[2].cache); - #line 1355 "Python/bytecodes.c" - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(dict->ma_keys)); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - res = entries[index].me_value; - DEOPT_IF(res == NULL, LOAD_GLOBAL); - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - #line 1915 "Python/generated_cases.c.h" + PyObject *_tmp_1; + PyObject *_tmp_2; + { + } + { + uint16_t version = read_u16(&next_instr[1].cache); + #line 1358 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)GLOBALS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + #line 1911 "Python/generated_cases.c.h" + } + { + } + { + PyObject *null = NULL; + PyObject *res; + uint16_t index = read_u16(&next_instr[3].cache); + #line 1372 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + res = entries[index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + #line 1927 "Python/generated_cases.c.h" + if (oparg & 1) { _tmp_2 = null; } + _tmp_1 = res; + } + next_instr += 4; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } - next_instr += 4; + stack_pointer[-1] = _tmp_1; + if (oparg & 1) { stack_pointer[-2] = _tmp_2; } DISPATCH(); } TARGET(LOAD_GLOBAL_BUILTIN) { - PyObject *null = NULL; - PyObject *res; - uint16_t index = read_u16(&next_instr[1].cache); - uint16_t mod_version = read_u16(&next_instr[2].cache); - uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1368 "Python/bytecodes.c" - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); - DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); - PyDictObject *mdict = (PyDictObject *)GLOBALS(); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - assert(opcode == LOAD_GLOBAL_BUILTIN); - DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); - DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(bdict->ma_keys)); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); - res = entries[index].me_value; - DEOPT_IF(res == NULL, LOAD_GLOBAL); - Py_INCREF(res); - STAT_INC(LOAD_GLOBAL, hit); - null = NULL; - #line 1945 "Python/generated_cases.c.h" + PyObject *_tmp_1; + PyObject *_tmp_2; + { + } + { + uint16_t version = read_u16(&next_instr[1].cache); + #line 1358 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)GLOBALS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + #line 1951 "Python/generated_cases.c.h" + } + { + uint16_t version = read_u16(&next_instr[2].cache); + #line 1365 "Python/bytecodes.c" + PyDictObject *dict = (PyDictObject *)BUILTINS(); + DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + #line 1960 "Python/generated_cases.c.h" + } + { + PyObject *null = NULL; + PyObject *res; + uint16_t index = read_u16(&next_instr[3].cache); + #line 1382 "Python/bytecodes.c" + PyDictObject *bdict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + res = entries[index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + #line 1974 "Python/generated_cases.c.h" + if (oparg & 1) { _tmp_2 = null; } + _tmp_1 = res; + } + next_instr += 4; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } - next_instr += 4; + stack_pointer[-1] = _tmp_1; + if (oparg & 1) { stack_pointer[-2] = _tmp_2; } DISPATCH(); } TARGET(DELETE_FAST) { - #line 1385 "Python/bytecodes.c" + #line 1404 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1959 "Python/generated_cases.c.h" + #line 1991 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1391 "Python/bytecodes.c" + #line 1410 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1969,12 +2001,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1973 "Python/generated_cases.c.h" + #line 2005 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1402 "Python/bytecodes.c" + #line 1421 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1985,14 +2017,14 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1989 "Python/generated_cases.c.h" + #line 2021 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1415 "Python/bytecodes.c" + #line 1434 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -2011,14 +2043,14 @@ } Py_INCREF(value); } - #line 2015 "Python/generated_cases.c.h" + #line 2047 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1436 "Python/bytecodes.c" + #line 1455 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2026,7 +2058,7 @@ if (true) goto error; } Py_INCREF(value); - #line 2030 "Python/generated_cases.c.h" + #line 2062 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2034,18 +2066,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1446 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2043 "Python/generated_cases.c.h" + #line 2075 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1453 "Python/bytecodes.c" + #line 1472 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2056,22 +2088,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2060 "Python/generated_cases.c.h" + #line 2092 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1466 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2069 "Python/generated_cases.c.h" + #line 2101 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1468 "Python/bytecodes.c" + #line 1487 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2075 "Python/generated_cases.c.h" + #line 2107 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2081,10 +2113,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1472 "Python/bytecodes.c" + #line 1491 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2088 "Python/generated_cases.c.h" + #line 2120 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2094,10 +2126,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1477 "Python/bytecodes.c" + #line 1496 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2101 "Python/generated_cases.c.h" + #line 2133 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2107,7 +2139,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1482 "Python/bytecodes.c" + #line 1501 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2118,13 +2150,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2122 "Python/generated_cases.c.h" + #line 2154 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1493 "Python/bytecodes.c" + #line 1512 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2128 "Python/generated_cases.c.h" + #line 2160 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2133,13 +2165,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1500 "Python/bytecodes.c" + #line 1519 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2139 "Python/generated_cases.c.h" + #line 2171 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1502 "Python/bytecodes.c" + #line 1521 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2143 "Python/generated_cases.c.h" + #line 2175 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2147,7 +2179,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1506 "Python/bytecodes.c" + #line 1525 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2162,7 +2194,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2166 "Python/generated_cases.c.h" + #line 2198 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2172,7 +2204,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1523 "Python/bytecodes.c" + #line 1542 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2180,13 +2212,13 @@ if (map == NULL) goto error; - #line 2184 "Python/generated_cases.c.h" + #line 2216 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1531 "Python/bytecodes.c" + #line 1550 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2190 "Python/generated_cases.c.h" + #line 2222 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2194,7 +2226,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1535 "Python/bytecodes.c" + #line 1554 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2232,7 +2264,7 @@ Py_DECREF(ann_dict); } } - #line 2236 "Python/generated_cases.c.h" + #line 2268 "Python/generated_cases.c.h" DISPATCH(); } @@ -2240,7 +2272,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1575 "Python/bytecodes.c" + #line 1594 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2250,14 +2282,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2254 "Python/generated_cases.c.h" + #line 2286 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1585 "Python/bytecodes.c" + #line 1604 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2261 "Python/generated_cases.c.h" + #line 2293 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2265,7 +2297,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1589 "Python/bytecodes.c" + #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2273,12 +2305,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2277 "Python/generated_cases.c.h" + #line 2309 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1597 "Python/bytecodes.c" + #line 1616 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2282 "Python/generated_cases.c.h" + #line 2314 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2286,17 +2318,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1603 "Python/bytecodes.c" + #line 1622 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2295 "Python/generated_cases.c.h" + #line 2327 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1608 "Python/bytecodes.c" + #line 1627 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2300 "Python/generated_cases.c.h" + #line 2332 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2305,25 +2337,25 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1614 "Python/bytecodes.c" + #line 1633 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2315 "Python/generated_cases.c.h" + #line 2347 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1622 "Python/bytecodes.c" + #line 1641 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2327 "Python/generated_cases.c.h" + #line 2359 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2334,7 +2366,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1636 "Python/bytecodes.c" + #line 1655 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2376,16 +2408,16 @@ } } } - #line 2380 "Python/generated_cases.c.h" + #line 2412 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1678 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2389 "Python/generated_cases.c.h" + #line 2421 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2400,20 +2432,20 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1697 "Python/bytecodes.c" + #line 1716 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2411 "Python/generated_cases.c.h" + #line 2443 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1704 "Python/bytecodes.c" + #line 1723 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2417 "Python/generated_cases.c.h" + #line 2449 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2428,7 +2460,7 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1708 "Python/bytecodes.c" + #line 1727 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2451,7 +2483,7 @@ res = res2; res2 = NULL; } - #line 2455 "Python/generated_cases.c.h" + #line 2487 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2465,7 +2497,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1749 "Python/bytecodes.c" + #line 1768 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2499,9 +2531,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2503 "Python/generated_cases.c.h" + #line 2535 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1783 "Python/bytecodes.c" + #line 1802 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2510,12 +2542,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2514 "Python/generated_cases.c.h" + #line 2546 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1792 "Python/bytecodes.c" + #line 1811 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2519 "Python/generated_cases.c.h" + #line 2551 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2529,7 +2561,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1801 "Python/bytecodes.c" + #line 1820 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2542,7 +2574,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2546 "Python/generated_cases.c.h" + #line 2578 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2557,7 +2589,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1817 "Python/bytecodes.c" + #line 1836 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2570,7 +2602,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2574 "Python/generated_cases.c.h" + #line 2606 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2585,7 +2617,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1833 "Python/bytecodes.c" + #line 1852 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2612,7 +2644,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2616 "Python/generated_cases.c.h" + #line 2648 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2627,7 +2659,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1863 "Python/bytecodes.c" + #line 1882 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2637,7 +2669,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2641 "Python/generated_cases.c.h" + #line 2673 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2652,7 +2684,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1876 "Python/bytecodes.c" + #line 1895 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2664,7 +2696,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2668 "Python/generated_cases.c.h" + #line 2700 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2678,7 +2710,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1891 "Python/bytecodes.c" + #line 1910 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2702,7 +2734,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2706 "Python/generated_cases.c.h" + #line 2738 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2710,7 +2742,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1917 "Python/bytecodes.c" + #line 1936 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2736,7 +2768,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2740 "Python/generated_cases.c.h" + #line 2772 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2744,7 +2776,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1945 "Python/bytecodes.c" + #line 1964 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2762,7 +2794,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2766 "Python/generated_cases.c.h" + #line 2798 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2773,7 +2805,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1965 "Python/bytecodes.c" + #line 1984 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2812,7 +2844,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2816 "Python/generated_cases.c.h" + #line 2848 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2823,7 +2855,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2006 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2833,7 +2865,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2837 "Python/generated_cases.c.h" + #line 2869 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2845,7 +2877,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2025 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2858,10 +2890,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 2862 "Python/generated_cases.c.h" + #line 2894 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2038 "Python/bytecodes.c" + #line 2057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2869,7 +2901,7 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 2873 "Python/generated_cases.c.h" + #line 2905 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2880,7 +2912,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2048 "Python/bytecodes.c" + #line 2067 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2892,7 +2924,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2896 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2903,7 +2935,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2063 "Python/bytecodes.c" + #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2919,7 +2951,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2923 "Python/generated_cases.c.h" + #line 2955 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2930,7 +2962,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2082 "Python/bytecodes.c" + #line 2101 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2943,7 +2975,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2947 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2954,14 +2986,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2097 "Python/bytecodes.c" + #line 2116 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2960 "Python/generated_cases.c.h" + #line 2992 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2099 "Python/bytecodes.c" + #line 2118 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2965 "Python/generated_cases.c.h" + #line 2997 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2971,15 +3003,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2103 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2977 "Python/generated_cases.c.h" + #line 3009 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2105 "Python/bytecodes.c" + #line 2124 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2983 "Python/generated_cases.c.h" + #line 3015 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2990,12 +3022,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2110 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2996 "Python/generated_cases.c.h" + #line 3028 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2112 "Python/bytecodes.c" + #line 2131 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3003,10 +3035,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 3007 "Python/generated_cases.c.h" + #line 3039 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2120 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3015,7 +3047,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3019 "Python/generated_cases.c.h" + #line 3051 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3025,21 +3057,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2131 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3032 "Python/generated_cases.c.h" + #line 3064 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2134 "Python/bytecodes.c" + #line 2153 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3039 "Python/generated_cases.c.h" + #line 3071 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2139 "Python/bytecodes.c" + #line 2158 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3043 "Python/generated_cases.c.h" + #line 3075 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3048,15 +3080,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2143 "Python/bytecodes.c" + #line 2162 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3055 "Python/generated_cases.c.h" + #line 3087 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2146 "Python/bytecodes.c" + #line 2165 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3060 "Python/generated_cases.c.h" + #line 3092 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3065,25 +3097,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2150 "Python/bytecodes.c" + #line 2169 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3073 "Python/generated_cases.c.h" + #line 3105 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2156 "Python/bytecodes.c" + #line 2175 "Python/bytecodes.c" JUMPBY(oparg); - #line 3082 "Python/generated_cases.c.h" + #line 3114 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2160 "Python/bytecodes.c" + #line 2179 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); @@ -3102,12 +3134,12 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3106 "Python/generated_cases.c.h" + #line 3138 "Python/generated_cases.c.h" DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2191 "Python/bytecodes.c" + #line 2210 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); PyCodeObject *code = _PyFrame_GetCode(frame); @@ -3122,25 +3154,25 @@ goto resume_with_error; } goto resume_frame; - #line 3126 "Python/generated_cases.c.h" + #line 3158 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2208 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3134 "Python/generated_cases.c.h" + #line 3166 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2213 "Python/bytecodes.c" + #line 2232 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3144 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3150,25 +3182,25 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2218 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3160 "Python/generated_cases.c.h" + #line 3192 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2224 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" } - #line 3164 "Python/generated_cases.c.h" + #line 3196 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2213 "Python/bytecodes.c" + #line 2232 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3172 "Python/generated_cases.c.h" + #line 3204 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); @@ -3179,52 +3211,52 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2218 "Python/bytecodes.c" + #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3189 "Python/generated_cases.c.h" + #line 3221 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2224 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" } - #line 3193 "Python/generated_cases.c.h" + #line 3225 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2208 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3201 "Python/generated_cases.c.h" + #line 3233 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2232 "Python/bytecodes.c" + #line 2251 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3215 "Python/generated_cases.c.h" + #line 3247 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2241 "Python/bytecodes.c" + #line 2260 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3228 "Python/generated_cases.c.h" + #line 3260 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3235,16 +3267,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2249 "Python/bytecodes.c" + #line 2268 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3244 "Python/generated_cases.c.h" + #line 3276 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2254 "Python/bytecodes.c" + #line 2273 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3252,7 +3284,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3256 "Python/generated_cases.c.h" + #line 3288 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3261,10 +3293,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2264 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3268 "Python/generated_cases.c.h" + #line 3300 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3273,10 +3305,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2269 "Python/bytecodes.c" + #line 2288 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3280 "Python/generated_cases.c.h" + #line 3312 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3286,11 +3318,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2274 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3294 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3299,14 +3331,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2280 "Python/bytecodes.c" + #line 2299 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3306 "Python/generated_cases.c.h" + #line 3338 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2283 "Python/bytecodes.c" + #line 2302 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3310 "Python/generated_cases.c.h" + #line 3342 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3314,7 +3346,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2287 "Python/bytecodes.c" + #line 2306 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3337,11 +3369,11 @@ if (iter == NULL) { goto error; } - #line 3341 "Python/generated_cases.c.h" + #line 3373 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2310 "Python/bytecodes.c" + #line 2329 "Python/bytecodes.c" } - #line 3345 "Python/generated_cases.c.h" + #line 3377 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3351,7 +3383,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2328 "Python/bytecodes.c" + #line 2347 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3383,7 +3415,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3387 "Python/generated_cases.c.h" + #line 3419 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3391,7 +3423,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2362 "Python/bytecodes.c" + #line 2381 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3417,14 +3449,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3421 "Python/generated_cases.c.h" + #line 3453 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2390 "Python/bytecodes.c" + #line 2409 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3445,7 +3477,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3449 "Python/generated_cases.c.h" + #line 3481 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3455,7 +3487,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2413 "Python/bytecodes.c" + #line 2432 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3476,7 +3508,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3480 "Python/generated_cases.c.h" + #line 3512 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3486,7 +3518,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2436 "Python/bytecodes.c" + #line 2455 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3505,7 +3537,7 @@ if (next == NULL) { goto error; } - #line 3509 "Python/generated_cases.c.h" + #line 3541 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3514,7 +3546,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2457 "Python/bytecodes.c" + #line 2476 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3530,14 +3562,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3534 "Python/generated_cases.c.h" + #line 3566 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2475 "Python/bytecodes.c" + #line 2494 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3560,16 +3592,16 @@ Py_DECREF(enter); goto error; } - #line 3564 "Python/generated_cases.c.h" + #line 3596 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2498 "Python/bytecodes.c" + #line 2517 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3573 "Python/generated_cases.c.h" + #line 3605 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3580,7 +3612,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2507 "Python/bytecodes.c" + #line 2526 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3606,16 +3638,16 @@ Py_DECREF(enter); goto error; } - #line 3610 "Python/generated_cases.c.h" + #line 3642 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2533 "Python/bytecodes.c" + #line 2552 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3619 "Python/generated_cases.c.h" + #line 3651 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3627,7 +3659,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2542 "Python/bytecodes.c" + #line 2561 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3648,7 +3680,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3652 "Python/generated_cases.c.h" + #line 3684 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3657,7 +3689,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2581 "Python/bytecodes.c" + #line 2600 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3667,7 +3699,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3671 "Python/generated_cases.c.h" + #line 3703 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3681,7 +3713,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2593 "Python/bytecodes.c" + #line 2612 "Python/bytecodes.c" assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); @@ -3698,7 +3730,7 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - #line 3702 "Python/generated_cases.c.h" + #line 3734 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3712,7 +3744,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2612 "Python/bytecodes.c" + #line 2631 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3722,7 +3754,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3726 "Python/generated_cases.c.h" + #line 3758 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3737,7 +3769,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2624 "Python/bytecodes.c" + #line 2643 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3750,11 +3782,11 @@ keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3754 "Python/generated_cases.c.h" + #line 3786 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2637 "Python/bytecodes.c" + #line 2656 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3758 "Python/generated_cases.c.h" + #line 3790 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3768,7 +3800,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2641 "Python/bytecodes.c" + #line 2660 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3776,11 +3808,11 @@ assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3780 "Python/generated_cases.c.h" + #line 3812 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2649 "Python/bytecodes.c" + #line 2668 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3784 "Python/generated_cases.c.h" + #line 3816 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3794,7 +3826,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2653 "Python/bytecodes.c" + #line 2672 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3808,7 +3840,7 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3812 "Python/generated_cases.c.h" + #line 3844 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3817,16 +3849,16 @@ } TARGET(KW_NAMES) { - #line 2669 "Python/bytecodes.c" + #line 2688 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3825 "Python/generated_cases.c.h" + #line 3857 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2675 "Python/bytecodes.c" + #line 2694 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3839,7 +3871,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3843 "Python/generated_cases.c.h" + #line 3875 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3849,7 +3881,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2721 "Python/bytecodes.c" + #line 2740 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3931,7 +3963,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3935 "Python/generated_cases.c.h" + #line 3967 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3943,7 +3975,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2809 "Python/bytecodes.c" + #line 2828 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3953,7 +3985,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3957 "Python/generated_cases.c.h" + #line 3989 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3962,7 +3994,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2821 "Python/bytecodes.c" + #line 2840 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3988,7 +4020,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3992 "Python/generated_cases.c.h" + #line 4024 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3996,7 +4028,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2849 "Python/bytecodes.c" + #line 2868 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4032,7 +4064,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4036 "Python/generated_cases.c.h" + #line 4068 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4040,7 +4072,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2887 "Python/bytecodes.c" + #line 2906 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4050,7 +4082,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4054 "Python/generated_cases.c.h" + #line 4086 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4063,7 +4095,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2899 "Python/bytecodes.c" + #line 2918 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4074,7 +4106,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4078 "Python/generated_cases.c.h" + #line 4110 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4088,7 +4120,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2913 "Python/bytecodes.c" + #line 2932 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4099,7 +4131,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4103 "Python/generated_cases.c.h" + #line 4135 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4112,7 +4144,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2927 "Python/bytecodes.c" + #line 2946 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4163,12 +4195,12 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4167 "Python/generated_cases.c.h" + #line 4199 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2980 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4176,7 +4208,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4180 "Python/generated_cases.c.h" + #line 4212 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4186,7 +4218,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 3009 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4208,7 +4240,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4212 "Python/generated_cases.c.h" + #line 4244 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4222,7 +4254,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3015 "Python/bytecodes.c" + #line 3034 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4250,7 +4282,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4254 "Python/generated_cases.c.h" + #line 4286 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4264,7 +4296,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3046 "Python/bytecodes.c" + #line 3065 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4296,7 +4328,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4300 "Python/generated_cases.c.h" + #line 4332 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4310,7 +4342,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3081 "Python/bytecodes.c" + #line 3100 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4342,7 +4374,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4346 "Python/generated_cases.c.h" + #line 4378 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4356,7 +4388,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3116 "Python/bytecodes.c" + #line 3135 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4381,7 +4413,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4385 "Python/generated_cases.c.h" + #line 4417 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4394,7 +4426,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3143 "Python/bytecodes.c" + #line 3162 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4421,7 +4453,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4425 "Python/generated_cases.c.h" + #line 4457 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4433,7 +4465,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3173 "Python/bytecodes.c" + #line 3192 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4451,14 +4483,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4455 "Python/generated_cases.c.h" + #line 4487 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3193 "Python/bytecodes.c" + #line 3212 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4489,7 +4521,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4493 "Python/generated_cases.c.h" + #line 4525 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4502,7 +4534,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3227 "Python/bytecodes.c" + #line 3246 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4531,7 +4563,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4535 "Python/generated_cases.c.h" + #line 4567 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4544,7 +4576,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3259 "Python/bytecodes.c" + #line 3278 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4573,7 +4605,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4577 "Python/generated_cases.c.h" + #line 4609 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4586,7 +4618,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3291 "Python/bytecodes.c" + #line 3310 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4614,7 +4646,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4618 "Python/generated_cases.c.h" + #line 4650 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4624,9 +4656,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3322 "Python/bytecodes.c" + #line 3341 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4630 "Python/generated_cases.c.h" + #line 4662 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4635,7 +4667,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3326 "Python/bytecodes.c" + #line 3345 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4697,14 +4729,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4701 "Python/generated_cases.c.h" + #line 4733 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3388 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4708 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4715,7 +4747,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3394 "Python/bytecodes.c" + #line 3413 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4727,7 +4759,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4731 "Python/generated_cases.c.h" + #line 4763 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4735,7 +4767,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3408 "Python/bytecodes.c" + #line 3427 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4760,14 +4792,14 @@ default: Py_UNREACHABLE(); } - #line 4764 "Python/generated_cases.c.h" + #line 4796 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3435 "Python/bytecodes.c" + #line 3454 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4788,7 +4820,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4792 "Python/generated_cases.c.h" + #line 4824 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4796,15 +4828,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3458 "Python/bytecodes.c" + #line 3477 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4802 "Python/generated_cases.c.h" + #line 4834 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3460 "Python/bytecodes.c" + #line 3479 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4808 "Python/generated_cases.c.h" + #line 4840 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4814,14 +4846,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3464 "Python/bytecodes.c" + #line 3483 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4825 "Python/generated_cases.c.h" + #line 4857 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4829,7 +4861,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3473 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4840,7 +4872,7 @@ else { res = value; } - #line 4844 "Python/generated_cases.c.h" + #line 4876 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4849,12 +4881,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3486 "Python/bytecodes.c" + #line 3505 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4858 "Python/generated_cases.c.h" + #line 4890 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4863,10 +4895,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3493 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4870 "Python/generated_cases.c.h" + #line 4902 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4878,7 +4910,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3498 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4893,12 +4925,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4897 "Python/generated_cases.c.h" + #line 4929 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3513 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4902 "Python/generated_cases.c.h" + #line 4934 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4908,16 +4940,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3518 "Python/bytecodes.c" + #line 3537 "Python/bytecodes.c" assert(oparg >= 2); - #line 4914 "Python/generated_cases.c.h" + #line 4946 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3522 "Python/bytecodes.c" + #line 3541 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4929,48 +4961,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4933 "Python/generated_cases.c.h" + #line 4965 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3536 "Python/bytecodes.c" + #line 3555 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4939 "Python/generated_cases.c.h" + #line 4971 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3540 "Python/bytecodes.c" + #line 3559 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4947 "Python/generated_cases.c.h" + #line 4979 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3545 "Python/bytecodes.c" + #line 3564 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4958 "Python/generated_cases.c.h" + #line 4990 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3553 "Python/bytecodes.c" + #line 3572 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4969 "Python/generated_cases.c.h" + #line 5001 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3561 "Python/bytecodes.c" + #line 3580 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4982,12 +5014,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4986 "Python/generated_cases.c.h" + #line 5018 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3575 "Python/bytecodes.c" + #line 3594 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4999,30 +5031,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5003 "Python/generated_cases.c.h" + #line 5035 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3589 "Python/bytecodes.c" + #line 3608 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5014 "Python/generated_cases.c.h" + #line 5046 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3597 "Python/bytecodes.c" + #line 3616 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5021 "Python/generated_cases.c.h" + #line 5053 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3602 "Python/bytecodes.c" + #line 3621 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5028 "Python/generated_cases.c.h" + #line 5060 "Python/generated_cases.c.h" } From 7f55f58b6c97306da350f5b441d26f859e9d8f16 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 12 Jul 2023 09:12:39 -0700 Subject: [PATCH 370/446] gh-106656: Remove --emit-line-directives from regen-cases (#106657) If you prefer to see `#line` directives in generated_cases.c.h, run ``` make regen-cases CASESFLAG=-l ``` But please don't commit the result. --- Makefile.pre.in | 3 +- Python/executor_cases.c.h | 314 --------------------- Python/generated_cases.c.h | 548 ------------------------------------- 3 files changed, 2 insertions(+), 863 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index a1ceedbd4812c0..4b655513f656d7 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1543,10 +1543,11 @@ regen-opcode-targets: .PHONY: regen-cases regen-cases: # Regenerate various files from Python/bytecodes.c + # Pass CASESFLAG=-l to insert #line directives in the output PYTHONPATH=$(srcdir)/Tools/cases_generator \ $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ - --emit-line-directives \ + $(CASESFLAG) \ -o $(srcdir)/Python/generated_cases.c.h.new \ -m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \ -e $(srcdir)/Python/executor_cases.c.h.new \ diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 94536ed8ce5a10..1df8feba352cff 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9,11 +9,9 @@ case LOAD_FAST_CHECK: { PyObject *value; - #line 182 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - #line 17 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -21,11 +19,9 @@ case LOAD_FAST: { PyObject *value; - #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 29 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -33,11 +29,9 @@ case LOAD_FAST_AND_CLEAR: { PyObject *value; - #line 194 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; - #line 41 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -45,10 +39,8 @@ case LOAD_CONST: { PyObject *value; - #line 209 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); - #line 52 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -56,17 +48,13 @@ case STORE_FAST: { PyObject *value = stack_pointer[-1]; - #line 214 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 62 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case POP_TOP: { PyObject *value = stack_pointer[-1]; - #line 237 "Python/bytecodes.c" - #line 70 "Python/executor_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); break; @@ -74,9 +62,7 @@ case PUSH_NULL: { PyObject *res; - #line 241 "Python/bytecodes.c" res = NULL; - #line 80 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -85,9 +71,7 @@ case END_SEND: { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 260 "Python/bytecodes.c" Py_DECREF(receiver); - #line 91 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; break; @@ -96,13 +80,9 @@ case UNARY_NEGATIVE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 275 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 102 "Python/executor_cases.c.h" Py_DECREF(value); - #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 106 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -110,10 +90,8 @@ case UNARY_NOT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 281 "Python/bytecodes.c" assert(PyBool_Check(value)); res = Py_IsFalse(value) ? Py_True : Py_False; - #line 117 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -122,7 +100,6 @@ static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value = stack_pointer[-1]; PyObject *res; - #line 296 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -134,29 +111,23 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ int err = PyObject_IsTrue(value); - #line 138 "Python/executor_cases.c.h" Py_DECREF(value); - #line 308 "Python/bytecodes.c" if (err < 0) goto pop_1_error; res = err ? Py_True : Py_False; - #line 143 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } case TO_BOOL_BOOL: { PyObject *value = stack_pointer[-1]; - #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 153 "Python/executor_cases.c.h" break; } case TO_BOOL_INT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 318 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value)) { @@ -164,12 +135,9 @@ res = Py_False; } else { - #line 168 "Python/executor_cases.c.h" Py_DECREF(value); - #line 326 "Python/bytecodes.c" res = Py_True; } - #line 173 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -177,11 +145,9 @@ case TO_BOOL_LIST: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 331 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; - #line 185 "Python/executor_cases.c.h" Py_DECREF(value); stack_pointer[-1] = res; break; @@ -190,12 +156,10 @@ case TO_BOOL_NONE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 338 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_False; - #line 199 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -203,7 +167,6 @@ case TO_BOOL_STR: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 345 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (value == &_Py_STR(empty)) { @@ -212,12 +175,9 @@ } else { assert(Py_SIZE(value)); - #line 216 "Python/executor_cases.c.h" Py_DECREF(value); - #line 354 "Python/bytecodes.c" res = Py_True; } - #line 221 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -226,16 +186,12 @@ PyObject *value = stack_pointer[-1]; PyObject *res; uint32_t version = (uint32_t)operand; - #line 359 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 235 "Python/executor_cases.c.h" Py_DECREF(value); - #line 364 "Python/bytecodes.c" res = Py_True; - #line 239 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -243,13 +199,9 @@ case UNARY_INVERT: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 249 "Python/executor_cases.c.h" Py_DECREF(value); - #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 253 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -257,10 +209,8 @@ case _GUARD_BOTH_INT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 264 "Python/executor_cases.c.h" break; } @@ -268,13 +218,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 391 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 278 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -284,13 +232,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 399 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 294 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -300,13 +246,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 407 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 310 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -315,10 +259,8 @@ case _GUARD_BOTH_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 322 "Python/executor_cases.c.h" break; } @@ -326,13 +268,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 427 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 336 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -342,13 +282,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 435 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 352 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -358,13 +296,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 443 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 368 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -373,10 +309,8 @@ case _GUARD_BOTH_UNICODE: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 380 "Python/executor_cases.c.h" break; } @@ -384,13 +318,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 463 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 394 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -401,7 +333,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -413,12 +344,9 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 417 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 529 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 422 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -429,7 +357,6 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 533 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -442,7 +369,6 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 446 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -453,7 +379,6 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 548 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -466,7 +391,6 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 470 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -475,7 +399,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 563 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -489,7 +412,6 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 493 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -499,7 +421,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 579 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -513,7 +434,6 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 517 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -523,7 +443,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 595 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -531,14 +450,11 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 535 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 542 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -549,9 +465,7 @@ case LIST_APPEND: { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 555 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -559,13 +473,9 @@ case SET_ADD: { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 565 "Python/executor_cases.c.h" Py_DECREF(v); - #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 569 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -576,7 +486,6 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = (uint16_t)operand; - #line 651 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -591,13 +500,10 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 595 "Python/executor_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 666 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 601 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -606,7 +512,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 670 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -623,7 +528,6 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 627 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -632,13 +536,11 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 689 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 642 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -646,15 +548,11 @@ case DELETE_SUBSCR: { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 653 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 658 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -662,14 +560,10 @@ case CALL_INTRINSIC_1: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 669 "Python/executor_cases.c.h" Py_DECREF(value); - #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 673 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -678,15 +572,11 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 685 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 690 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -695,7 +585,6 @@ case GET_AITER: { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 819 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -708,16 +597,12 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 712 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 719 "Python/executor_cases.c.h" Py_DECREF(obj); - #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -730,7 +615,6 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 734 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -738,7 +622,6 @@ case GET_ANEXT: { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 852 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -781,7 +664,6 @@ Py_DECREF(next_iter); } } - #line 785 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -790,16 +672,13 @@ case GET_AWAITABLE: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 897 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 801 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 904 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -816,26 +695,21 @@ } if (iter == NULL) goto pop_1_error; - #line 820 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } case POP_EXCEPT: { PyObject *exc_value = stack_pointer[-1]; - #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 830 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case LOAD_ASSERTION_ERROR: { PyObject *value; - #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 839 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -843,14 +717,12 @@ case LOAD_BUILD_CLASS: { PyObject *bc; - #line 1089 "Python/bytecodes.c" if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc) < 0) goto error; if (bc == NULL) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); if (true) goto error; } - #line 854 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -858,33 +730,26 @@ case STORE_NAME: { PyObject *v = stack_pointer[-1]; - #line 1099 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 869 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1106 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 878 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1113 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 882 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_NAME: { - #line 1117 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -901,14 +766,12 @@ name); goto error; } - #line 905 "Python/executor_cases.c.h" break; } case UNPACK_SEQUENCE: { static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1143 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -921,11 +784,8 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 925 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1156 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 929 "Python/executor_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); break; @@ -934,14 +794,12 @@ case UNPACK_SEQUENCE_TWO_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1160 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 945 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -951,7 +809,6 @@ case UNPACK_SEQUENCE_TUPLE: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1170 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -959,7 +816,6 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 963 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -969,7 +825,6 @@ case UNPACK_SEQUENCE_LIST: { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1181 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -977,7 +832,6 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 981 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -986,49 +840,36 @@ case UNPACK_EX: { PyObject *seq = stack_pointer[-1]; - #line 1192 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 994 "Python/executor_cases.c.h" Py_DECREF(seq); - #line 1196 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 998 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; - #line 1227 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_DelAttr(owner, name); - #line 1008 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1230 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1012 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case STORE_GLOBAL: { PyObject *v = stack_pointer[-1]; - #line 1234 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1022 "Python/executor_cases.c.h" Py_DECREF(v); - #line 1237 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1026 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case DELETE_GLOBAL: { - #line 1241 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1040,13 +881,11 @@ } goto error; } - #line 1044 "Python/executor_cases.c.h" break; } case _LOAD_LOCALS: { PyObject *locals; - #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1054,7 +893,6 @@ if (true) goto error; } Py_INCREF(locals); - #line 1058 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -1063,7 +901,6 @@ case _LOAD_FROM_DICT_OR_GLOBALS: { PyObject *mod_or_class_dict = stack_pointer[-1]; PyObject *v; - #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { Py_DECREF(mod_or_class_dict); @@ -1090,7 +927,6 @@ } } } - #line 1094 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } @@ -1099,7 +935,6 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1146,7 +981,6 @@ } } null = NULL; - #line 1150 "Python/executor_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1160,37 +994,30 @@ case _GUARD_GLOBALS_VERSION: { uint16_t version = (uint16_t)operand; - #line 1358 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); - #line 1169 "Python/executor_cases.c.h" break; } case _GUARD_BUILTINS_VERSION: { uint16_t version = (uint16_t)operand; - #line 1365 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)BUILTINS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); - #line 1180 "Python/executor_cases.c.h" break; } case DELETE_FAST: { - #line 1404 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1189 "Python/executor_cases.c.h" break; } case DELETE_DEREF: { - #line 1421 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1201,14 +1028,12 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1205 "Python/executor_cases.c.h" break; } case LOAD_FROM_DICT_OR_DEREF: { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1434 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -1227,14 +1052,12 @@ } Py_INCREF(value); } - #line 1231 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } case LOAD_DEREF: { PyObject *value; - #line 1455 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1242,7 +1065,6 @@ if (true) goto error; } Py_INCREF(value); - #line 1246 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1250,18 +1072,15 @@ case STORE_DEREF: { PyObject *v = stack_pointer[-1]; - #line 1465 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1259 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } case COPY_FREE_VARS: { - #line 1472 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -1272,22 +1091,17 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1276 "Python/executor_cases.c.h" break; } case BUILD_STRING: { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1485 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1285 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1487 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1291 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1297,10 +1111,8 @@ case BUILD_TUPLE: { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1491 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1304 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1310,10 +1122,8 @@ case BUILD_LIST: { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1496 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1317 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1323,7 +1133,6 @@ case LIST_EXTEND: { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1501 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1334,13 +1143,10 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1338 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1512 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1344 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1349,13 +1155,9 @@ case SET_UPDATE: { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1519 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1355 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 1521 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1359 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1363,7 +1165,6 @@ case BUILD_SET: { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1525 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1378,7 +1179,6 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1382 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1388,7 +1188,6 @@ case BUILD_MAP: { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1542 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1396,13 +1195,10 @@ if (map == NULL) goto error; - #line 1400 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1550 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1406 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1410,7 +1206,6 @@ } case SETUP_ANNOTATIONS: { - #line 1554 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1448,7 +1243,6 @@ Py_DECREF(ann_dict); } } - #line 1452 "Python/executor_cases.c.h" break; } @@ -1456,7 +1250,6 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1594 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1466,14 +1259,11 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1470 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1604 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1477 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1481,7 +1271,6 @@ case DICT_UPDATE: { PyObject *update = stack_pointer[-1]; - #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1489,12 +1278,9 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1493 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1616 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1498 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1502,17 +1288,13 @@ case DICT_MERGE: { PyObject *update = stack_pointer[-1]; - #line 1622 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1511 "Python/executor_cases.c.h" Py_DECREF(update); - #line 1627 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1516 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1521,13 +1303,11 @@ case MAP_ADD: { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1633 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 1531 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1538,20 +1318,16 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1716 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1549 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1723 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1555 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1565,7 +1341,6 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1727 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1588,7 +1363,6 @@ res = res2; res2 = NULL; } - #line 1592 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -1600,7 +1374,6 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1768 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1634,9 +1407,7 @@ NULL | meth | arg1 | ... | argN */ - #line 1638 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1802 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1645,12 +1416,9 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 1649 "Python/executor_cases.c.h" Py_DECREF(owner); - #line 1811 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 1654 "Python/executor_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -1662,7 +1430,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1675,10 +1442,8 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 1679 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -1686,7 +1451,6 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 1690 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1696,7 +1460,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2067 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1708,7 +1471,6 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1712 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1718,7 +1480,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -1734,7 +1495,6 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1738 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1744,7 +1504,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2101 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -1757,7 +1516,6 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1761 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1767,14 +1525,10 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2116 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1773 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2118 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1778 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1784,15 +1538,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2122 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1790 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2124 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1796 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1803,12 +1553,9 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2129 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1809 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2131 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -1816,10 +1563,8 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1820 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2139 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -1828,7 +1573,6 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1832 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1838,21 +1582,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2150 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1845 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2153 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1852 "Python/executor_cases.c.h" Py_DECREF(right); - #line 2158 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1856 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1860,17 +1598,13 @@ case IS_NONE: { PyObject *value = stack_pointer[-1]; PyObject *b; - #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 1870 "Python/executor_cases.c.h" Py_DECREF(value); - #line 2243 "Python/bytecodes.c" } - #line 1874 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1878,13 +1612,11 @@ case GET_LEN: { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2260 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1888 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1895,16 +1627,13 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2268 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1904 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2273 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -1912,7 +1641,6 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1916 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1921,10 +1649,8 @@ case MATCH_MAPPING: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2283 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1928 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1933,10 +1659,8 @@ case MATCH_SEQUENCE: { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2288 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1940 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1946,11 +1670,9 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2293 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1954 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1959,14 +1681,10 @@ case GET_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2299 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1966 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2302 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1970 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1974,7 +1692,6 @@ case GET_YIELD_FROM_ITER: { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2306 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -1997,11 +1714,8 @@ if (iter == NULL) { goto error; } - #line 2001 "Python/executor_cases.c.h" Py_DECREF(iterable); - #line 2329 "Python/bytecodes.c" } - #line 2005 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -2011,7 +1725,6 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2561 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2032,7 +1745,6 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 2036 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -2041,7 +1753,6 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2600 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2051,7 +1762,6 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 2055 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2060,7 +1770,6 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 2999 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2068,7 +1777,6 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 2072 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -2076,7 +1784,6 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3413 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2088,7 +1795,6 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 2092 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -2096,7 +1802,6 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3427 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2121,7 +1826,6 @@ default: Py_UNREACHABLE(); } - #line 2125 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -2132,15 +1836,11 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3477 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 2138 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3479 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 2144 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -2150,14 +1850,12 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3483 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 2161 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -2165,7 +1863,6 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3492 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2176,7 +1873,6 @@ else { res = value; } - #line 2180 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -2185,12 +1881,10 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3505 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 2194 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2199,10 +1893,8 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3512 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 2206 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -2213,7 +1905,6 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2228,12 +1919,9 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 2232 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3532 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2237 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2242,9 +1930,7 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3537 "Python/bytecodes.c" assert(oparg >= 2); - #line 2248 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index fcdf732315830a..f7a18b43ff11f9 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,6 @@ } TARGET(RESUME) { - #line 136 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); /* Possibly combine this with eval breaker */ @@ -20,12 +19,10 @@ else if (oparg < 2) { CHECK_EVAL_BREAKER(); } - #line 24 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_RESUME) { - #line 150 "Python/bytecodes.c" /* Possible performance enhancement: * We need to check the eval breaker anyway, can we * combine the instrument verison check and the eval breaker test? @@ -51,17 +48,14 @@ DISPATCH(); } } - #line 55 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 182 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - #line 65 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -69,11 +63,9 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 188 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - #line 77 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -81,11 +73,9 @@ TARGET(LOAD_FAST_AND_CLEAR) { PyObject *value; - #line 194 "Python/bytecodes.c" value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; - #line 89 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -94,14 +84,12 @@ TARGET(LOAD_FAST_LOAD_FAST) { PyObject *value1; PyObject *value2; - #line 200 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; value1 = GETLOCAL(oparg1); value2 = GETLOCAL(oparg2); Py_INCREF(value1); Py_INCREF(value2); - #line 105 "Python/generated_cases.c.h" STACK_GROW(2); stack_pointer[-1] = value2; stack_pointer[-2] = value1; @@ -110,10 +98,8 @@ TARGET(LOAD_CONST) { PyObject *value; - #line 209 "Python/bytecodes.c" value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); - #line 117 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -121,9 +107,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 214 "Python/bytecodes.c" SETLOCAL(oparg, value); - #line 127 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -131,13 +115,11 @@ TARGET(STORE_FAST_LOAD_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2; - #line 222 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); value2 = GETLOCAL(oparg2); Py_INCREF(value2); - #line 141 "Python/generated_cases.c.h" stack_pointer[-1] = value2; DISPATCH(); } @@ -145,20 +127,16 @@ TARGET(STORE_FAST_STORE_FAST) { PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; - #line 230 "Python/bytecodes.c" uint32_t oparg1 = oparg >> 4; uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); SETLOCAL(oparg2, value2); - #line 154 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 237 "Python/bytecodes.c" - #line 162 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -166,9 +144,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 241 "Python/bytecodes.c" res = NULL; - #line 172 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -179,14 +155,10 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 237 "Python/bytecodes.c" - #line 184 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 237 "Python/bytecodes.c" - #line 190 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); @@ -196,7 +168,6 @@ TARGET(INSTRUMENTED_END_FOR) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 247 "Python/bytecodes.c" /* Need to create a fake StopIteration error here, * to conform to PEP 380 */ if (PyGen_Check(receiver)) { @@ -206,7 +177,6 @@ } PyErr_SetRaisedException(NULL); } - #line 210 "Python/generated_cases.c.h" Py_DECREF(receiver); Py_DECREF(value); STACK_SHRINK(2); @@ -216,9 +186,7 @@ TARGET(END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 260 "Python/bytecodes.c" Py_DECREF(receiver); - #line 222 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -227,7 +195,6 @@ TARGET(INSTRUMENTED_END_SEND) { PyObject *value = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 264 "Python/bytecodes.c" if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) { PyErr_SetObject(PyExc_StopIteration, value); if (monitor_stop_iteration(tstate, frame, next_instr-1)) { @@ -236,7 +203,6 @@ PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); - #line 240 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; DISPATCH(); @@ -245,13 +211,9 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 275 "Python/bytecodes.c" res = PyNumber_Negative(value); - #line 251 "Python/generated_cases.c.h" Py_DECREF(value); - #line 277 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 255 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -259,10 +221,8 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 281 "Python/bytecodes.c" assert(PyBool_Check(value)); res = Py_IsFalse(value) ? Py_True : Py_False; - #line 266 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -272,7 +232,6 @@ static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value = stack_pointer[-1]; PyObject *res; - #line 296 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -284,12 +243,9 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ int err = PyObject_IsTrue(value); - #line 288 "Python/generated_cases.c.h" Py_DECREF(value); - #line 308 "Python/bytecodes.c" if (err < 0) goto pop_1_error; res = err ? Py_True : Py_False; - #line 293 "Python/generated_cases.c.h" stack_pointer[-1] = res; next_instr += 3; DISPATCH(); @@ -297,10 +253,8 @@ TARGET(TO_BOOL_BOOL) { PyObject *value = stack_pointer[-1]; - #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 304 "Python/generated_cases.c.h" next_instr += 3; DISPATCH(); } @@ -308,7 +262,6 @@ TARGET(TO_BOOL_INT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 318 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (_PyLong_IsZero((PyLongObject *)value)) { @@ -316,12 +269,9 @@ res = Py_False; } else { - #line 320 "Python/generated_cases.c.h" Py_DECREF(value); - #line 326 "Python/bytecodes.c" res = Py_True; } - #line 325 "Python/generated_cases.c.h" stack_pointer[-1] = res; next_instr += 3; DISPATCH(); @@ -330,11 +280,9 @@ TARGET(TO_BOOL_LIST) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 331 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; - #line 338 "Python/generated_cases.c.h" Py_DECREF(value); stack_pointer[-1] = res; next_instr += 3; @@ -344,12 +292,10 @@ TARGET(TO_BOOL_NONE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 338 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_False; - #line 353 "Python/generated_cases.c.h" stack_pointer[-1] = res; next_instr += 3; DISPATCH(); @@ -358,7 +304,6 @@ TARGET(TO_BOOL_STR) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 345 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); if (value == &_Py_STR(empty)) { @@ -367,12 +312,9 @@ } else { assert(Py_SIZE(value)); - #line 371 "Python/generated_cases.c.h" Py_DECREF(value); - #line 354 "Python/bytecodes.c" res = Py_True; } - #line 376 "Python/generated_cases.c.h" stack_pointer[-1] = res; next_instr += 3; DISPATCH(); @@ -382,16 +324,12 @@ PyObject *value = stack_pointer[-1]; PyObject *res; uint32_t version = read_u32(&next_instr[1].cache); - #line 359 "Python/bytecodes.c" // This one is a bit weird, because we expect *some* failures: assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 391 "Python/generated_cases.c.h" Py_DECREF(value); - #line 364 "Python/bytecodes.c" res = Py_True; - #line 395 "Python/generated_cases.c.h" stack_pointer[-1] = res; next_instr += 3; DISPATCH(); @@ -400,13 +338,9 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 406 "Python/generated_cases.c.h" Py_DECREF(value); - #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 410 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -417,10 +351,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 424 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -428,13 +360,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 391 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 438 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -449,10 +379,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 456 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -460,13 +388,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 399 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 470 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -481,10 +407,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 488 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -492,13 +416,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 407 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 502 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -513,10 +435,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 520 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -524,13 +444,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 427 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 534 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -545,10 +463,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 552 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -556,13 +472,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 435 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 566 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -577,10 +491,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 584 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -588,13 +500,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 443 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); double dres = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 598 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -609,10 +519,8 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 616 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } @@ -620,13 +528,11 @@ PyObject *right = _tmp_1; PyObject *left = _tmp_2; PyObject *res; - #line 463 "Python/bytecodes.c" STAT_INC(BINARY_OP, hit); res = PyUnicode_Concat(left, right); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 630 "Python/generated_cases.c.h" _tmp_2 = res; } next_instr += 1; @@ -641,17 +547,14 @@ { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 648 "Python/generated_cases.c.h" _tmp_2 = left; _tmp_1 = right; } { PyObject *right = _tmp_1; PyObject *left = _tmp_2; - #line 480 "Python/bytecodes.c" _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; assert(true_next.op.code == STORE_FAST); PyObject **target_local = &GETLOCAL(true_next.op.arg); @@ -675,7 +578,6 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - #line 679 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -687,7 +589,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -699,12 +600,9 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); - #line 703 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 529 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 708 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -716,7 +614,6 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 533 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -729,7 +626,6 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 733 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -740,7 +636,6 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 548 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -753,7 +648,6 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 757 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -762,7 +656,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 563 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -776,7 +669,6 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 780 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -787,7 +679,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 579 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -801,7 +692,6 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 805 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -812,7 +702,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 595 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyDict_GetItemWithError(dict, sub); @@ -820,14 +709,11 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 824 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 831 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -839,7 +725,6 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 610 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); @@ -862,15 +747,12 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 866 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 874 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -878,13 +760,9 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 884 "Python/generated_cases.c.h" Py_DECREF(v); - #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 888 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -896,7 +774,6 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 651 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { next_instr--; @@ -911,13 +788,10 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 915 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 666 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 921 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -927,7 +801,6 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 670 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -944,7 +817,6 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 948 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -954,13 +826,11 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 689 "Python/bytecodes.c" DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 964 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -969,15 +839,11 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 976 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 981 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -985,14 +851,10 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 992 "Python/generated_cases.c.h" Py_DECREF(value); - #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 996 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -1001,15 +863,11 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 1008 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 1013 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -1017,7 +875,6 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 718 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -1035,12 +892,10 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 1039 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 738 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); /* Restore previous cframe and return. */ @@ -1049,12 +904,10 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 1053 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 749 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1067,12 +920,10 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1071 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 764 "Python/bytecodes.c" int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, frame, next_instr-1, retval); @@ -1089,11 +940,9 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1093 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 783 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -1107,11 +956,9 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1111 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_RETURN_CONST) { - #line 799 "Python/bytecodes.c" PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_RETURN, @@ -1129,13 +976,11 @@ frame->prev_instr += frame->return_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1133 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 819 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -1148,16 +993,12 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 1152 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 1159 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -1170,7 +1011,6 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 1174 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1178,7 +1018,6 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 852 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1221,7 +1060,6 @@ Py_DECREF(next_iter); } } - #line 1225 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; DISPATCH(); @@ -1230,16 +1068,13 @@ TARGET(GET_AWAITABLE) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 897 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 1241 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 904 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1256,7 +1091,6 @@ } if (iter == NULL) goto pop_1_error; - #line 1260 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -1267,7 +1101,6 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 928 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1314,7 +1147,6 @@ } } Py_DECREF(v); - #line 1318 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1323,7 +1155,6 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 977 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, SEND); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1339,12 +1170,10 @@ tstate->exc_info = &gen->gi_exc_state; SKIP_OVER(INLINE_CACHE_ENTRIES_SEND); DISPATCH_INLINED(gen_frame); - #line 1343 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 995 "Python/bytecodes.c" assert(frame != &entry_frame); assert(oparg >= 0); /* make the generator identify this as HAS_ARG */ PyGenObject *gen = _PyFrame_GetGenerator(frame); @@ -1362,12 +1191,10 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1366 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 1015 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1384,15 +1211,12 @@ gen_frame->previous = NULL; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1388 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1396 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1400,7 +1224,6 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 1039 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1418,26 +1241,21 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1422 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 1059 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1431 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 1062 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1441 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1448,23 +1266,19 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 1071 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1457 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 1076 "Python/bytecodes.c" none = Py_None; } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1468 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1473,9 +1287,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1479 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1483,14 +1295,12 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 1089 "Python/bytecodes.c" if (PyMapping_GetOptionalItem(BUILTINS(), &_Py_ID(__build_class__), &bc) < 0) goto error; if (bc == NULL) { _PyErr_SetString(tstate, PyExc_NameError, "__build_class__ not found"); if (true) goto error; } - #line 1494 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1498,33 +1308,26 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 1099 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1509 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1106 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1518 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1113 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1522 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 1117 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); int err; @@ -1541,7 +1344,6 @@ name); goto error; } - #line 1545 "Python/generated_cases.c.h" DISPATCH(); } @@ -1549,7 +1351,6 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 1143 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1562,11 +1363,8 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1566 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1156 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1570 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1576,14 +1374,12 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1160 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1587 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1594,7 +1390,6 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1170 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1602,7 +1397,6 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1606 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1613,7 +1407,6 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 1181 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1621,7 +1414,6 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1625 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1631,15 +1423,11 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 1192 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1639 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 1196 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1643 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1650,7 +1438,6 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 1207 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1666,12 +1453,9 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1670 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 1223 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1675 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1679,34 +1463,25 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 1227 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_DelAttr(owner, name); - #line 1686 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1230 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1690 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 1234 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1700 "Python/generated_cases.c.h" Py_DECREF(v); - #line 1237 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1704 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 1241 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1718,7 +1493,6 @@ } goto error; } - #line 1722 "Python/generated_cases.c.h" DISPATCH(); } @@ -1726,7 +1500,6 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1734,7 +1507,6 @@ if (true) goto error; } Py_INCREF(locals); - #line 1738 "Python/generated_cases.c.h" _tmp_1 = locals; } STACK_GROW(1); @@ -1746,7 +1518,6 @@ PyObject *_tmp_1; { PyObject *locals; - #line 1255 "Python/bytecodes.c" locals = LOCALS(); if (locals == NULL) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1754,13 +1525,11 @@ if (true) goto error; } Py_INCREF(locals); - #line 1758 "Python/generated_cases.c.h" _tmp_1 = locals; } { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { Py_DECREF(mod_or_class_dict); @@ -1787,7 +1556,6 @@ } } } - #line 1791 "Python/generated_cases.c.h" _tmp_1 = v; } STACK_GROW(1); @@ -1800,7 +1568,6 @@ { PyObject *mod_or_class_dict = _tmp_1; PyObject *v; - #line 1267 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) { Py_DECREF(mod_or_class_dict); @@ -1827,7 +1594,6 @@ } } } - #line 1831 "Python/generated_cases.c.h" _tmp_1 = v; } stack_pointer[-1] = _tmp_1; @@ -1839,7 +1605,6 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1306 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1886,7 +1651,6 @@ } } null = NULL; - #line 1890 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1902,12 +1666,10 @@ } { uint16_t version = read_u16(&next_instr[1].cache); - #line 1358 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); - #line 1911 "Python/generated_cases.c.h" } { } @@ -1915,7 +1677,6 @@ PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[3].cache); - #line 1372 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)GLOBALS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); res = entries[index].me_value; @@ -1923,7 +1684,6 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1927 "Python/generated_cases.c.h" if (oparg & 1) { _tmp_2 = null; } _tmp_1 = res; } @@ -1942,27 +1702,22 @@ } { uint16_t version = read_u16(&next_instr[1].cache); - #line 1358 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)GLOBALS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); - #line 1951 "Python/generated_cases.c.h" } { uint16_t version = read_u16(&next_instr[2].cache); - #line 1365 "Python/bytecodes.c" PyDictObject *dict = (PyDictObject *)BUILTINS(); DEOPT_IF(!PyDict_CheckExact(dict), LOAD_GLOBAL); DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); - #line 1960 "Python/generated_cases.c.h" } { PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[3].cache); - #line 1382 "Python/bytecodes.c" PyDictObject *bdict = (PyDictObject *)BUILTINS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); res = entries[index].me_value; @@ -1970,7 +1725,6 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1974 "Python/generated_cases.c.h" if (oparg & 1) { _tmp_2 = null; } _tmp_1 = res; } @@ -1983,16 +1737,13 @@ } TARGET(DELETE_FAST) { - #line 1404 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1991 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1410 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -2001,12 +1752,10 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 2005 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1421 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -2017,14 +1766,12 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 2021 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_FROM_DICT_OR_DEREF) { PyObject *class_dict = stack_pointer[-1]; PyObject *value; - #line 1434 "Python/bytecodes.c" PyObject *name; assert(class_dict); assert(oparg >= 0 && oparg < _PyFrame_GetCode(frame)->co_nlocalsplus); @@ -2043,14 +1790,12 @@ } Py_INCREF(value); } - #line 2047 "Python/generated_cases.c.h" stack_pointer[-1] = value; DISPATCH(); } TARGET(LOAD_DEREF) { PyObject *value; - #line 1455 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -2058,7 +1803,6 @@ if (true) goto error; } Py_INCREF(value); - #line 2062 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -2066,18 +1810,15 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1465 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 2075 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1472 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = _PyFrame_GetCode(frame); assert(PyFunction_Check(frame->f_funcobj)); @@ -2088,22 +1829,17 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 2092 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1485 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 2101 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1487 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2107 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -2113,10 +1849,8 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1491 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2120 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -2126,10 +1860,8 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1496 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 2133 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -2139,7 +1871,6 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1501 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -2150,13 +1881,10 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 2154 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1512 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 2160 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -2165,13 +1893,9 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1519 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 2171 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1521 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 2175 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -2179,7 +1903,6 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1525 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -2194,7 +1917,6 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 2198 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -2204,7 +1926,6 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1542 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -2212,13 +1933,10 @@ if (map == NULL) goto error; - #line 2216 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1550 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 2222 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -2226,7 +1944,6 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1554 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -2264,7 +1981,6 @@ Py_DECREF(ann_dict); } } - #line 2268 "Python/generated_cases.c.h" DISPATCH(); } @@ -2272,7 +1988,6 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1594 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -2282,14 +1997,11 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 2286 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1604 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 2293 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -2297,7 +2009,6 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1608 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -2305,12 +2016,9 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 2309 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1616 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2314 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2318,17 +2026,13 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1622 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2327 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1627 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2332 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2337,25 +2041,21 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1633 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2347 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } TARGET(INSTRUMENTED_LOAD_SUPER_ATTR) { - #line 1641 "Python/bytecodes.c" _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - #line 2359 "Python/generated_cases.c.h" } TARGET(LOAD_SUPER_ATTR) { @@ -2366,7 +2066,6 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1655 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -2408,16 +2107,13 @@ } } } - #line 2412 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1697 "Python/bytecodes.c" if (super == NULL) goto pop_3_error; res = PyObject_GetAttr(super, name); Py_DECREF(super); if (res == NULL) goto pop_3_error; - #line 2421 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2432,20 +2128,16 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2 = NULL; PyObject *res; - #line 1716 "Python/bytecodes.c" assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 2443 "Python/generated_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - #line 1723 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 2449 "Python/generated_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2460,7 +2152,6 @@ PyObject *global_super = stack_pointer[-3]; PyObject *res2; PyObject *res; - #line 1727 "Python/bytecodes.c" assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -2483,7 +2174,6 @@ res = res2; res2 = NULL; } - #line 2487 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; @@ -2497,7 +2187,6 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1768 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2531,9 +2220,7 @@ NULL | meth | arg1 | ... | argN */ - #line 2535 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1802 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2542,12 +2229,9 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2546 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1811 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2551 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2561,7 +2245,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1820 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2574,7 +2257,6 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2578 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2589,7 +2271,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1836 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2602,7 +2283,6 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2606 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2617,7 +2297,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1852 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2644,7 +2323,6 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2648 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2659,7 +2337,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1882 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2669,7 +2346,6 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2673 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2684,7 +2360,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1895 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2696,7 +2371,6 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2700 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2710,7 +2384,6 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1910 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2734,7 +2407,6 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2738 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2742,7 +2414,6 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1936 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2768,7 +2439,6 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2772 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2776,7 +2446,6 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1964 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2794,7 +2463,6 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2798 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2805,7 +2473,6 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1984 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2844,7 +2511,6 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2848 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2855,7 +2521,6 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2025 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2865,7 +2530,6 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2869 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2877,7 +2541,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2890,10 +2553,8 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 2894 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; if (oparg & 16) { int res_bool = PyObject_IsTrue(res); @@ -2901,7 +2562,6 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 2905 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2912,7 +2572,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2067 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2924,7 +2583,6 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2935,7 +2593,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2082 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2951,7 +2608,6 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2955 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2962,7 +2618,6 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2101 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2975,7 +2630,6 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 2979 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2986,14 +2640,10 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2116 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2992 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2118 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2997 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3003,15 +2653,11 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2122 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 3009 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2124 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 3015 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3022,12 +2668,9 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2129 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 3028 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2131 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3035,10 +2678,8 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 3039 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2139 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3047,7 +2688,6 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3051 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3057,21 +2697,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2150 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3064 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2153 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3071 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2158 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3075 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3080,15 +2714,11 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2162 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3087 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2165 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3092 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3097,25 +2727,20 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2169 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3105 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2175 "Python/bytecodes.c" JUMPBY(oparg); - #line 3114 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2179 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); @@ -3134,12 +2759,10 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3138 "Python/generated_cases.c.h" DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2210 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); PyCodeObject *code = _PyFrame_GetCode(frame); @@ -3154,25 +2777,20 @@ goto resume_with_error; } goto resume_frame; - #line 3158 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2227 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3166 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2232 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3176 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3182,25 +2800,19 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3192 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2243 "Python/bytecodes.c" } - #line 3196 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2232 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3204 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); @@ -3211,52 +2823,42 @@ { PyObject *value = _tmp_1; PyObject *b; - #line 2237 "Python/bytecodes.c" if (Py_IsNone(value)) { b = Py_True; } else { b = Py_False; - #line 3221 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2243 "Python/bytecodes.c" } - #line 3225 "Python/generated_cases.c.h" _tmp_1 = b; } { PyObject *cond = _tmp_1; - #line 2227 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3233 "Python/generated_cases.c.h" } STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2251 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 3247 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2260 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3260 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3267,16 +2869,13 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2268 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3276 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2273 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3284,7 +2883,6 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3288 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3293,10 +2891,8 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2283 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3300 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3305,10 +2901,8 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2288 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3312 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3318,11 +2912,9 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2293 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3326 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3331,14 +2923,10 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2299 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3338 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2302 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3342 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3346,7 +2934,6 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2306 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3369,11 +2956,8 @@ if (iter == NULL) { goto error; } - #line 3373 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2329 "Python/bytecodes.c" } - #line 3377 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3383,7 +2967,6 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2347 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3415,7 +2998,6 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3419 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3423,7 +3005,6 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2381 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3449,14 +3030,12 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3453 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2409 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3477,7 +3056,6 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3481 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3487,7 +3065,6 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2432 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3508,7 +3085,6 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3512 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3518,7 +3094,6 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2455 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3537,7 +3112,6 @@ if (next == NULL) { goto error; } - #line 3541 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3546,7 +3120,6 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2476 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3562,14 +3135,12 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3566 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2494 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3592,16 +3163,13 @@ Py_DECREF(enter); goto error; } - #line 3596 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2517 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3605 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3612,7 +3180,6 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2526 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3638,16 +3205,13 @@ Py_DECREF(enter); goto error; } - #line 3642 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2552 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3651 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3659,7 +3223,6 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2561 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3680,7 +3243,6 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3684 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3689,7 +3251,6 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2600 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3699,7 +3260,6 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3703 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3713,7 +3273,6 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2612 "Python/bytecodes.c" assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); @@ -3730,7 +3289,6 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - #line 3734 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3744,7 +3302,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2631 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3754,7 +3311,6 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3758 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3769,7 +3325,6 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2643 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3782,11 +3337,8 @@ keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3786 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2656 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3790 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3800,7 +3352,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2660 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3808,11 +3359,8 @@ assert(self_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - #line 3812 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2668 "Python/bytecodes.c" res = Py_NewRef(descr); - #line 3816 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); stack_pointer[-1] = res; if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } @@ -3826,7 +3374,6 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2672 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3840,7 +3387,6 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - #line 3844 "Python/generated_cases.c.h" STACK_GROW((1 ? 1 : 0)); stack_pointer[-1] = res; if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } @@ -3849,16 +3395,13 @@ } TARGET(KW_NAMES) { - #line 2688 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3857 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2694 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3871,7 +3414,6 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3875 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3881,7 +3423,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2740 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3963,7 +3504,6 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3967 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3975,7 +3515,6 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2828 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3985,7 +3524,6 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3989 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3994,7 +3532,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2840 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4020,7 +3557,6 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4024 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4028,7 +3564,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2868 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4064,7 +3599,6 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4068 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4072,7 +3606,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2906 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4082,7 +3615,6 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4086 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4095,7 +3627,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2918 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4106,7 +3637,6 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4110 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4120,7 +3650,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2932 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4131,7 +3660,6 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4135 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4144,7 +3672,6 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2946 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4195,12 +3722,10 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4199 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2999 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4208,7 +3733,6 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4212 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4218,7 +3742,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3009 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4240,7 +3763,6 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4244 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4254,7 +3776,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3034 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4282,7 +3803,6 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4286 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4296,7 +3816,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3065 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4328,7 +3847,6 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4332 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4342,7 +3860,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3100 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4374,7 +3891,6 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4378 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4388,7 +3904,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3135 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4413,7 +3928,6 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4417 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4426,7 +3940,6 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3162 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4453,7 +3966,6 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4457 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4465,7 +3977,6 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3192 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4483,14 +3994,12 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4487 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3212 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4521,7 +4030,6 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4525 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4534,7 +4042,6 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3246 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4563,7 +4070,6 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4567 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4576,7 +4082,6 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3278 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4605,7 +4110,6 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4609 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4618,7 +4122,6 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3310 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4646,7 +4149,6 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4650 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4656,9 +4158,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3341 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4662 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4667,7 +4167,6 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3345 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4729,14 +4228,11 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4733 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3407 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4740 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4747,7 +4243,6 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3413 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4759,7 +4254,6 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4763 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4767,7 +4261,6 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3427 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4792,14 +4285,12 @@ default: Py_UNREACHABLE(); } - #line 4796 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3454 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4820,7 +4311,6 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4824 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4828,15 +4318,11 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3477 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4834 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3479 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4840 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4846,14 +4332,12 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3483 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4857 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4861,7 +4345,6 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3492 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4872,7 +4355,6 @@ else { res = value; } - #line 4876 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4881,12 +4363,10 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3505 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4890 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4895,10 +4375,8 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3512 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4902 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4910,7 +4388,6 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3517 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4925,12 +4402,9 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4929 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3532 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4934 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4940,16 +4414,13 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3537 "Python/bytecodes.c" assert(oparg >= 2); - #line 4946 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3541 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4961,48 +4432,38 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4965 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3555 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4971 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3559 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4979 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3564 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4990 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3572 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5001 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3580 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5014,12 +4475,10 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5018 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3594 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5031,30 +4490,23 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5035 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3608 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5046 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3616 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5053 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3621 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5060 "Python/generated_cases.c.h" } From dd1884dc5dc1a540c60e98ea1bc482a51d996564 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 12 Jul 2023 10:23:59 -0700 Subject: [PATCH 371/446] gh-106529: Split FOR_ITER_RANGE into uops (#106638) For an example of what this does for Tier 1 and Tier 2, see https://github.com/python/cpython/issues/106529#issuecomment-1631649920 --- Include/internal/pycore_opcode_metadata.h | 6 +++ Lib/test/test_capi/test_misc.py | 25 ++++++++-- Python/bytecodes.c | 27 +++++++++-- Python/executor_cases.c.h | 34 +++++++++++++ Python/generated_cases.c.h | 58 +++++++++++++++-------- Python/optimizer.c | 24 +++++++++- 6 files changed, 146 insertions(+), 28 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 317f42afea8049..d2c1f9ad6e5fb3 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -40,6 +40,9 @@ #define _GUARD_GLOBALS_VERSION 318 #define _GUARD_BUILTINS_VERSION 319 #define IS_NONE 320 +#define _ITER_CHECK_RANGE 321 +#define _ITER_EXHAUSTED_RANGE 322 +#define _ITER_NEXT_RANGE 323 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1319,5 +1322,8 @@ const char * const _PyOpcode_uop_name[512] = { [318] = "_GUARD_GLOBALS_VERSION", [319] = "_GUARD_BUILTINS_VERSION", [320] = "IS_NONE", + [321] = "_ITER_CHECK_RANGE", + [322] = "_ITER_EXHAUSTED_RANGE", + [323] = "_ITER_NEXT_RANGE", }; #endif // NEED_OPCODE_METADATA diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9c14a501875b6d..abdf7ed8976350 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2443,7 +2443,6 @@ def testfunc(x): i += 1 opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): testfunc(1000) @@ -2580,13 +2579,33 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - # for i, (opname, oparg) in enumerate(ex): - # print(f"{i:4d}: {opname:<20s} {oparg:4d}") uops = {opname for opname, _ in ex} # Since there is no JUMP_FORWARD instruction, # look for indirect evidence: the += operator self.assertIn("_BINARY_OP_ADD_INT", uops) + def test_for_iter_range(self): + def testfunc(n): + total = 0 + for i in range(n): + total += i + return total + # import dis; dis.dis(testfunc) + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + total = testfunc(10) + self.assertEqual(total, 45) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + # for i, (opname, oparg) in enumerate(ex): + # print(f"{i:4d}: {opname:<20s} {oparg:3d}") + uops = {opname for opname, _ in ex} + self.assertIn("_ITER_EXHAUSTED_RANGE", uops) + # Verification that the jump goes past END_FOR + # is done by manual inspection of the output + if __name__ == "__main__": unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f5ce2e72d26762..18862f87b65fa0 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2451,9 +2451,14 @@ dummy_func( // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { + op(_ITER_CHECK_RANGE, (iter -- iter)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); + } + + op(_ITER_JUMP_RANGE, (iter -- iter)) { + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); STAT_INC(FOR_ITER, hit); if (r->len <= 0) { STACK_SHRINK(1); @@ -2463,15 +2468,29 @@ dummy_func( JUMPBY(oparg + 1); DISPATCH(); } + } + + // Only used by Tier 2 + op(_ITER_EXHAUSTED_RANGE, (iter -- iter, exhausted)) { + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + exhausted = r->len <= 0 ? Py_True : Py_False; + } + + op(_ITER_NEXT_RANGE, (iter -- iter, next)) { + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + assert(r->len > 0); long value = r->start; r->start = value + r->step; r->len--; next = PyLong_FromLong(value); - if (next == NULL) { - goto error; - } + ERROR_IF(next == NULL, error); } + macro(FOR_ITER_RANGE) = + unused/1 + _ITER_CHECK_RANGE + _ITER_JUMP_RANGE + _ITER_NEXT_RANGE; + inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1df8feba352cff..2c2dbf429cec11 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1720,6 +1720,40 @@ break; } + case _ITER_CHECK_RANGE: { + PyObject *iter = stack_pointer[-1]; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); + break; + } + + case _ITER_EXHAUSTED_RANGE: { + PyObject *iter = stack_pointer[-1]; + PyObject *exhausted; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + exhausted = r->len <= 0 ? Py_True : Py_False; + STACK_GROW(1); + stack_pointer[-1] = exhausted; + break; + } + + case _ITER_NEXT_RANGE: { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + assert(r->len > 0); + long value = r->start; + r->start = value + r->step; + r->len--; + next = PyLong_FromLong(value); + if (next == NULL) goto error; + STACK_GROW(1); + stack_pointer[-1] = next; + break; + } + case WITH_EXCEPT_START: { PyObject *val = stack_pointer[-1]; PyObject *lasti = stack_pointer[-3]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f7a18b43ff11f9..383432f51a89ac 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3092,29 +3092,47 @@ } TARGET(FOR_ITER_RANGE) { - PyObject *iter = stack_pointer[-1]; - PyObject *next; - _PyRangeIterObject *r = (_PyRangeIterObject *)iter; - DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); - STAT_INC(FOR_ITER, hit); - if (r->len <= 0) { - STACK_SHRINK(1); - Py_DECREF(r); - SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); - // Jump over END_FOR instruction. - JUMPBY(oparg + 1); - DISPATCH(); + PyObject *_tmp_1; + PyObject *_tmp_2 = stack_pointer[-1]; + { + PyObject *iter = _tmp_2; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); + _tmp_2 = iter; } - long value = r->start; - r->start = value + r->step; - r->len--; - next = PyLong_FromLong(value); - if (next == NULL) { - goto error; + { + PyObject *iter = _tmp_2; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + STAT_INC(FOR_ITER, hit); + if (r->len <= 0) { + STACK_SHRINK(1); + Py_DECREF(r); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); + // Jump over END_FOR instruction. + JUMPBY(oparg + 1); + DISPATCH(); + } + _tmp_2 = iter; + } + { + PyObject *iter = _tmp_2; + PyObject *next; + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + assert(r->len > 0); + long value = r->start; + r->start = value + r->step; + r->len--; + next = PyLong_FromLong(value); + if (next == NULL) goto error; + _tmp_2 = iter; + _tmp_1 = next; } - STACK_GROW(1); - stack_pointer[-1] = next; next_instr += 1; + STACK_GROW(1); + stack_pointer[-1] = _tmp_1; + stack_pointer[-2] = _tmp_2; DISPATCH(); } diff --git a/Python/optimizer.c b/Python/optimizer.c index c3fdee63a7ed48..abd2351f6b78bd 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -479,6 +479,28 @@ translate_bytecode_to_trace( break; } + case FOR_ITER_RANGE: + { + // Assume jump unlikely (can a for-loop exit be likely?) + // Reserve 9 entries (4 here, 3 stub, plus SAVE_IP + EXIT_TRACE) + if (trace_length + 9 > max_length) { + DPRINTF(1, "Ran out of space for FOR_ITER_RANGE\n"); + goto done; + } + _Py_CODEUNIT *target_instr = // +1 at the end skips over END_FOR + instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg + 1; + max_length -= 3; // Really the start of the stubs + ADD_TO_TRACE(_ITER_CHECK_RANGE, 0); + ADD_TO_TRACE(_ITER_EXHAUSTED_RANGE, 0); + ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length); + ADD_TO_TRACE(_ITER_NEXT_RANGE, 0); + + ADD_TO_STUB(max_length + 0, POP_TOP, 0); + ADD_TO_STUB(max_length + 1, SAVE_IP, INSTR_IP(target_instr, code)); + ADD_TO_STUB(max_length + 2, EXIT_TRACE, 0); + break; + } + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -574,8 +596,8 @@ translate_bytecode_to_trace( } } } - trace_length += buffer_size - max_length; } + trace_length += buffer_size - max_length; return trace_length; } else { From e4b88c1e4ac129b36f99a534387d64f7b8cda8ef Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 12 Jul 2023 21:07:59 +0300 Subject: [PATCH 372/446] gh-106236: Replace `assert` with `raise RuntimeError` in `threading.py` (#106237) Replace `assert` with `raise ` in `threading.py` so that -OO does not alter _DummyThread behavior. --- Lib/test/test_threading.py | 8 ++++++++ Lib/threading.py | 7 ++++--- .../2023-06-29-15-10-44.gh-issue-106236.EAIX4l.rst | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-29-15-10-44.gh-issue-106236.EAIX4l.rst diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 9e4972ecb640df..4a91eef31c4b8b 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -251,6 +251,14 @@ def f(mutex): #Issue 29376 self.assertTrue(threading._active[tid].is_alive()) self.assertRegex(repr(threading._active[tid]), '_DummyThread') + + # Issue gh-106236: + with self.assertRaises(RuntimeError): + threading._active[tid].join() + threading._active[tid]._started.clear() + with self.assertRaises(RuntimeError): + threading._active[tid].is_alive() + del threading._active[tid] # PyThreadState_SetAsyncExc() is a CPython-only gimmick, not (currently) diff --git a/Lib/threading.py b/Lib/threading.py index df273870fa4273..e036cb891e196d 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -1451,11 +1451,12 @@ def _stop(self): pass def is_alive(self): - assert not self._is_stopped and self._started.is_set() - return True + if not self._is_stopped and self._started.is_set(): + return True + raise RuntimeError("thread is not alive") def join(self, timeout=None): - assert False, "cannot join a dummy thread" + raise RuntimeError("cannot join a dummy thread") # Global API functions diff --git a/Misc/NEWS.d/next/Library/2023-06-29-15-10-44.gh-issue-106236.EAIX4l.rst b/Misc/NEWS.d/next/Library/2023-06-29-15-10-44.gh-issue-106236.EAIX4l.rst new file mode 100644 index 00000000000000..036bdb6ef59f6c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-29-15-10-44.gh-issue-106236.EAIX4l.rst @@ -0,0 +1,2 @@ +Replace ``assert`` statements with ``raise RuntimeError`` in +:mod:`threading`, so that ``_DummyThread`` cannot be joined even with ``-OO``. From 357e9e9da3929cb9d55ea31896e66f488e44e8f2 Mon Sep 17 00:00:00 2001 From: Prince Roshan Date: Thu, 13 Jul 2023 02:31:17 +0530 Subject: [PATCH 373/446] gh-106602: [Enum] Add __copy__ and __deepcopy__ (GH-106666) --- Lib/enum.py | 6 ++++++ Lib/test/test_enum.py | 8 ++++++++ .../2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst | 1 + 3 files changed, 15 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst diff --git a/Lib/enum.py b/Lib/enum.py index 202f0da028bdfe..0c985b2c778569 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1218,6 +1218,12 @@ def __hash__(self): def __reduce_ex__(self, proto): return self.__class__, (self._value_, ) + def __deepcopy__(self,memo): + return self + + def __copy__(self): + return self + # enum.property is used to provide access to the `name` and # `value` attributes of enum members while keeping some measure of # protection from modification, while still allowing for an enumeration diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index adb1e0e52c5485..a286411f7bcf57 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -804,9 +804,17 @@ def test_copy(self): TE = self.MainEnum copied = copy.copy(TE) self.assertEqual(copied, TE) + self.assertIs(copied, TE) deep = copy.deepcopy(TE) self.assertEqual(deep, TE) + self.assertIs(deep, TE) + def test_copy_member(self): + TE = self.MainEnum + copied = copy.copy(TE.first) + self.assertIs(copied, TE.first) + deep = copy.deepcopy(TE.first) + self.assertIs(deep, TE.first) class _FlagTests: diff --git a/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst b/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst new file mode 100644 index 00000000000000..d9c122f1d3c723 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-12-04-58-45.gh-issue-106602.dGCcXe.rst @@ -0,0 +1 @@ +Add __copy__ and __deepcopy__ in :mod:`enum` From a180e7a0df342e9f089998fc680be83ad2e49a79 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 12 Jul 2023 22:33:47 +0100 Subject: [PATCH 374/446] gh-104050: Argument clinic: Annotate the `Destination` class (#106655) Co-authored-by: Nikita Sobolev --- Tools/clinic/clinic.py | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index a0cf50b29c978d..ce3039cdd8bff4 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1954,27 +1954,32 @@ def dump(self): return "".join(texts) +@dc.dataclass(slots=True, repr=False) class Destination: - def __init__(self, name, type, clinic, *args): - self.name = name - self.type = type - self.clinic = clinic - self.buffers = BufferSeries() + name: str + type: str + clinic: Clinic + buffers: BufferSeries = dc.field(init=False, default_factory=BufferSeries) + filename: str = dc.field(init=False) # set in __post_init__ + args: dc.InitVar[tuple[str, ...]] = () + + def __post_init__(self, args: tuple[str, ...]) -> None: valid_types = ('buffer', 'file', 'suppress') - if type not in valid_types: + if self.type not in valid_types: fail( - f"Invalid destination type {type!r} for {name}, " + f"Invalid destination type {self.type!r} for {self.name}, " f"must be {', '.join(valid_types)}" ) - extra_arguments = 1 if type == "file" else 0 + extra_arguments = 1 if self.type == "file" else 0 if len(args) < extra_arguments: - fail(f"Not enough arguments for destination {name} new {type}") + fail(f"Not enough arguments for destination {self.name} new {self.type}") if len(args) > extra_arguments: - fail(f"Too many arguments for destination {name} new {type}") - if type =='file': + fail(f"Too many arguments for destination {self.name} new {self.type}") + if self.type =='file': d = {} - filename = clinic.filename + filename = self.clinic.filename + assert filename is not None d['path'] = filename dirname, basename = os.path.split(filename) if not dirname: @@ -1984,19 +1989,19 @@ def __init__(self, name, type, clinic, *args): d['basename_root'], d['basename_extension'] = os.path.splitext(filename) self.filename = args[0].format_map(d) - def __repr__(self): + def __repr__(self) -> str: if self.type == 'file': file_repr = " " + repr(self.filename) else: file_repr = '' return "".join(("")) - def clear(self): + def clear(self) -> None: if self.type != 'buffer': fail("Can't clear destination" + self.name + " , it's not of type buffer") self.buffers.clear() - def dump(self): + def dump(self) -> str: return self.buffers.dump() @@ -2164,11 +2169,11 @@ def add_destination( self, name: str, type: str, - *args + *args: str ) -> None: if name in self.destinations: fail("Destination already exists: " + repr(name)) - self.destinations[name] = Destination(name, type, self, *args) + self.destinations[name] = Destination(name, type, self, args) def get_destination(self, name: str) -> Destination: d = self.destinations.get(name) From 8aa4beaad0d95917b1bb12d146bc15c1aa815e08 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 12 Jul 2023 23:48:36 +0100 Subject: [PATCH 375/446] gh-104683: Argument clinic: modernise `cpp.Monitor` (#106698) --- Tools/clinic/cpp.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Tools/clinic/cpp.py b/Tools/clinic/cpp.py index c1a2eeef22deca..fbac81336b545e 100644 --- a/Tools/clinic/cpp.py +++ b/Tools/clinic/cpp.py @@ -1,3 +1,4 @@ +import dataclasses as dc import re import sys from collections.abc import Callable @@ -15,6 +16,11 @@ def negate(condition: str) -> str: return condition[1:] return "!" + condition + +is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match + + +@dc.dataclass(repr=False) class Monitor: """ A simple C preprocessor that scans C source and computes, line by line, @@ -27,25 +33,20 @@ class Monitor: Anyway this implementation seems to work well enough for the CPython sources. """ + filename: str | None = None + _: dc.KW_ONLY + verbose: bool = False - is_a_simple_defined: Callable[[str], re.Match[str] | None] - is_a_simple_defined = re.compile(r'^defined\s*\(\s*[A-Za-z0-9_]+\s*\)$').match - - def __init__(self, filename: str | None = None, *, verbose: bool = False) -> None: + def __post_init__(self) -> None: self.stack: TokenStack = [] self.in_comment = False self.continuation: str | None = None self.line_number = 0 - self.filename = filename - self.verbose = verbose def __repr__(self) -> str: - return ''.join(( - '")) + return ( + f"" + ) def status(self) -> str: return str(self.line_number).rjust(4) + ": " + self.condition() @@ -152,7 +153,7 @@ def pop_stack() -> TokenAndCondition: if not condition: self.fail("Invalid format for #" + token + " line: no argument!") if token in {'if', 'elif'}: - if not self.is_a_simple_defined(condition): + if not is_a_simple_defined(condition): condition = "(" + condition + ")" if token == 'elif': previous_token, previous_condition = pop_stack() From 2d43beec225a0495ffa0344f961b99717e5f1106 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 13 Jul 2023 00:49:30 +0200 Subject: [PATCH 376/446] gh-104050: Argument Clinic: Annotate nested function parser_body() in the CLanguage class (#106699) --- Tools/clinic/clinic.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index ce3039cdd8bff4..8a75aba1e4de93 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -898,22 +898,24 @@ def output_templates(self, f): # parser_body_fields remembers the fields passed in to the # previous call to parser_body. this is used for an awful hack. parser_body_fields = () - def parser_body(prototype, *fields, declarations=''): + def parser_body( + prototype: str, + *fields: str, + declarations: str = '' + ) -> str: nonlocal parser_body_fields add, output = text_accumulator() add(prototype) parser_body_fields = fields - fields = list(fields) - fields.insert(0, normalize_snippet(""" + preamble = normalize_snippet(""" {{ {return_value_declaration} {parser_declarations} {declarations} {initializers} - """) + "\n") - # just imagine--your code is here in the middle - fields.append(normalize_snippet(""" + """) + "\n" + finale = normalize_snippet(""" {modifications} {return_value} = {c_basename}_impl({impl_arguments}); {return_conversion} @@ -923,8 +925,8 @@ def parser_body(prototype, *fields, declarations=''): {cleanup} return return_value; }} - """)) - for field in fields: + """) + for field in preamble, *fields, finale: add('\n') add(field) return linear_format(output(), parser_declarations=declarations) From ab86426a3472ab68747815299d390b213793c3d1 Mon Sep 17 00:00:00 2001 From: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> Date: Wed, 12 Jul 2023 22:50:45 -0400 Subject: [PATCH 377/446] gh-105235: Prevent reading outside buffer during mmap.find() (#105252) * Add a special case for s[-m:] == p in _PyBytes_Find * Add tests for _PyBytes_Find * Make sure that start <= end in mmap.find --- Lib/test/test_mmap.py | 21 ++++ ...-06-02-19-37-29.gh-issue-105235.fgFGTi.rst | 1 + Modules/_testinternalcapi.c | 114 ++++++++++++++++++ Modules/mmapmodule.c | 7 +- Objects/bytesobject.c | 21 +++- 5 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 517cbe0cb115ab..bab868600895c1 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -299,6 +299,27 @@ def test_find_end(self): self.assertEqual(m.find(b'one', 1, -2), -1) self.assertEqual(m.find(bytearray(b'one')), 0) + for i in range(-n-1, n+1): + for j in range(-n-1, n+1): + for p in [b"o", b"on", b"two", b"ones", b"s"]: + expected = data.find(p, i, j) + self.assertEqual(m.find(p, i, j), expected, (p, i, j)) + + def test_find_does_not_access_beyond_buffer(self): + try: + flags = mmap.MAP_PRIVATE | mmap.MAP_ANONYMOUS + PAGESIZE = mmap.PAGESIZE + PROT_NONE = 0 + PROT_READ = mmap.PROT_READ + except AttributeError as e: + raise unittest.SkipTest("mmap flags unavailable") from e + for i in range(0, 2049): + with mmap.mmap(-1, PAGESIZE * (i + 1), + flags=flags, prot=PROT_NONE) as guard: + with mmap.mmap(-1, PAGESIZE * (i + 2048), + flags=flags, prot=PROT_READ) as fm: + fm.find(b"fo", -2) + def test_rfind(self): # test the new 'end' parameter works as expected diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst new file mode 100644 index 00000000000000..c28d0101cd4bad --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-02-19-37-29.gh-issue-105235.fgFGTi.rst @@ -0,0 +1 @@ +Prevent out-of-bounds memory access during ``mmap.find()`` calls. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 52e524a40672ed..7745dd5abc22f0 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -14,6 +14,7 @@ #include "interpreteridobject.h" // _PyInterpreterID_LookUp() #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() +#include "pycore_bytesobject.h" // _PyBytes_Find() #include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble #include "pycore_ceval.h" // _PyEval_AddPendingCall #include "pycore_fileutils.h" // _Py_normpath @@ -443,6 +444,118 @@ test_edit_cost(PyObject *self, PyObject *Py_UNUSED(args)) } +static int +check_bytes_find(const char *haystack0, const char *needle0, + int offset, Py_ssize_t expected) +{ + Py_ssize_t len_haystack = strlen(haystack0); + Py_ssize_t len_needle = strlen(needle0); + Py_ssize_t result_1 = _PyBytes_Find(haystack0, len_haystack, + needle0, len_needle, offset); + if (result_1 != expected) { + PyErr_Format(PyExc_AssertionError, + "Incorrect result_1: '%s' in '%s' (offset=%zd)", + needle0, haystack0, offset); + return -1; + } + // Allocate new buffer with no NULL terminator. + char *haystack = PyMem_Malloc(len_haystack); + if (haystack == NULL) { + PyErr_NoMemory(); + return -1; + } + char *needle = PyMem_Malloc(len_needle); + if (needle == NULL) { + PyMem_Free(haystack); + PyErr_NoMemory(); + return -1; + } + memcpy(haystack, haystack0, len_haystack); + memcpy(needle, needle0, len_needle); + Py_ssize_t result_2 = _PyBytes_Find(haystack, len_haystack, + needle, len_needle, offset); + PyMem_Free(haystack); + PyMem_Free(needle); + if (result_2 != expected) { + PyErr_Format(PyExc_AssertionError, + "Incorrect result_2: '%s' in '%s' (offset=%zd)", + needle0, haystack0, offset); + return -1; + } + return 0; +} + +static int +check_bytes_find_large(Py_ssize_t len_haystack, Py_ssize_t len_needle, + const char *needle) +{ + char *zeros = PyMem_RawCalloc(len_haystack, 1); + if (zeros == NULL) { + PyErr_NoMemory(); + return -1; + } + Py_ssize_t res = _PyBytes_Find(zeros, len_haystack, needle, len_needle, 0); + PyMem_RawFree(zeros); + if (res != -1) { + PyErr_Format(PyExc_AssertionError, + "check_bytes_find_large(%zd, %zd) found %zd", + len_haystack, len_needle, res); + return -1; + } + return 0; +} + +static PyObject * +test_bytes_find(PyObject *self, PyObject *Py_UNUSED(args)) +{ + #define CHECK(H, N, O, E) do { \ + if (check_bytes_find(H, N, O, E) < 0) { \ + return NULL; \ + } \ + } while (0) + + CHECK("", "", 0, 0); + CHECK("Python", "", 0, 0); + CHECK("Python", "", 3, 3); + CHECK("Python", "", 6, 6); + CHECK("Python", "yth", 0, 1); + CHECK("ython", "yth", 1, 1); + CHECK("thon", "yth", 2, -1); + CHECK("Python", "thon", 0, 2); + CHECK("ython", "thon", 1, 2); + CHECK("thon", "thon", 2, 2); + CHECK("hon", "thon", 3, -1); + CHECK("Pytho", "zz", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ab", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "ba", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bb", 0, -1); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", "ab", 0, 30); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaba", "ba", 0, 30); + CHECK("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb", "bb", 0, 30); + #undef CHECK + + // Hunt for segfaults + // n, m chosen here so that (n - m) % (m + 1) == 0 + // This would make default_find in fastsearch.h access haystack[n]. + if (check_bytes_find_large(2048, 2, "ab") < 0) { + return NULL; + } + if (check_bytes_find_large(4096, 16, "0123456789abcdef") < 0) { + return NULL; + } + if (check_bytes_find_large(8192, 2, "ab") < 0) { + return NULL; + } + if (check_bytes_find_large(16384, 4, "abcd") < 0) { + return NULL; + } + if (check_bytes_find_large(32768, 2, "ab") < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + static PyObject * normalize_path(PyObject *self, PyObject *filename) { @@ -1328,6 +1441,7 @@ static PyMethodDef module_functions[] = { {"reset_path_config", test_reset_path_config, METH_NOARGS}, {"test_atomic_funcs", test_atomic_funcs, METH_NOARGS}, {"test_edit_cost", test_edit_cost, METH_NOARGS}, + {"test_bytes_find", test_bytes_find, METH_NOARGS}, {"normalize_path", normalize_path, METH_O, NULL}, {"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL}, {"EncodeLocaleEx", encode_locale_ex, METH_VARARGS}, diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index fef27123a3282b..c1cd5b0efaa3d2 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -342,12 +342,17 @@ mmap_gfind(mmap_object *self, Py_ssize_t res; CHECK_VALID_OR_RELEASE(NULL, view); - if (reverse) { + if (end < start) { + res = -1; + } + else if (reverse) { + assert(0 <= start && start <= end && end <= self->size); res = _PyBytes_ReverseFind( self->data + start, end - start, view.buf, view.len, start); } else { + assert(0 <= start && start <= end && end <= self->size); res = _PyBytes_Find( self->data + start, end - start, view.buf, view.len, start); diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 477bc4d31e812b..6b9231a9fa7693 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1272,8 +1272,25 @@ _PyBytes_Find(const char *haystack, Py_ssize_t len_haystack, const char *needle, Py_ssize_t len_needle, Py_ssize_t offset) { - return stringlib_find(haystack, len_haystack, - needle, len_needle, offset); + assert(len_haystack >= 0); + assert(len_needle >= 0); + // Extra checks because stringlib_find accesses haystack[len_haystack]. + if (len_needle == 0) { + return offset; + } + if (len_needle > len_haystack) { + return -1; + } + assert(len_haystack >= 1); + Py_ssize_t res = stringlib_find(haystack, len_haystack - 1, + needle, len_needle, offset); + if (res == -1) { + Py_ssize_t last_align = len_haystack - len_needle; + if (memcmp(haystack + last_align, needle, len_needle) == 0) { + return offset + last_align; + } + } + return res; } Py_ssize_t From af51bd7cda9c0cba149b882c1e501765595e5fc3 Mon Sep 17 00:00:00 2001 From: Jim Porter <826865+jimporter@users.noreply.github.com> Date: Wed, 12 Jul 2023 23:08:33 -0700 Subject: [PATCH 378/446] =?UTF-8?q?gh-89427:=20Set=20VIRTUAL=5FENV=5FPROMP?= =?UTF-8?q?T=20even=20when=20VIRTUAL=5FENV=5FDISABLE=5FPROMPT=E2=80=A6=20(?= =?UTF-8?q?GH-106643)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/venv/scripts/common/Activate.ps1 | 3 ++- Lib/venv/scripts/common/activate | 5 +++-- Lib/venv/scripts/posix/activate.csh | 2 +- Lib/venv/scripts/posix/activate.fish | 2 +- .../Library/2023-07-11-12-34-04.gh-issue-89427.GOkCp9.rst | 2 ++ 5 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-11-12-34-04.gh-issue-89427.GOkCp9.rst diff --git a/Lib/venv/scripts/common/Activate.ps1 b/Lib/venv/scripts/common/Activate.ps1 index eeea3583fa130d..d75b8fbcfc7778 100644 --- a/Lib/venv/scripts/common/Activate.ps1 +++ b/Lib/venv/scripts/common/Activate.ps1 @@ -219,6 +219,8 @@ deactivate -nondestructive # that there is an activated venv. $env:VIRTUAL_ENV = $VenvDir +$env:VIRTUAL_ENV_PROMPT = $Prompt + if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { Write-Verbose "Setting prompt to '$Prompt'" @@ -233,7 +235,6 @@ if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " _OLD_VIRTUAL_PROMPT } - $env:VIRTUAL_ENV_PROMPT = $Prompt } # Clear PYTHONHOME diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate index 408df5cb93b9e9..458740a35b0d20 100644 --- a/Lib/venv/scripts/common/activate +++ b/Lib/venv/scripts/common/activate @@ -52,6 +52,9 @@ _OLD_VIRTUAL_PATH="$PATH" PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" export PATH +VIRTUAL_ENV_PROMPT="__VENV_PROMPT__" +export VIRTUAL_ENV_PROMPT + # unset PYTHONHOME if set # this will fail if PYTHONHOME is set to the empty string (which is bad anyway) # could use `if (set -u; : $PYTHONHOME) ;` in bash @@ -64,8 +67,6 @@ if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then _OLD_VIRTUAL_PS1="${PS1:-}" PS1="__VENV_PROMPT__${PS1:-}" export PS1 - VIRTUAL_ENV_PROMPT="__VENV_PROMPT__" - export VIRTUAL_ENV_PROMPT fi # This should detect bash and zsh, which have a hash command that must diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh index 5e8d66fa9e5061..9caf138a919a86 100644 --- a/Lib/venv/scripts/posix/activate.csh +++ b/Lib/venv/scripts/posix/activate.csh @@ -13,13 +13,13 @@ setenv VIRTUAL_ENV "__VENV_DIR__" set _OLD_VIRTUAL_PATH="$PATH" setenv PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH" +setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" set _OLD_VIRTUAL_PROMPT="$prompt" if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then set prompt = "__VENV_PROMPT__$prompt" - setenv VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" endif alias pydoc python -m pydoc diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish index 91ad6442e05692..565df23d1e2a13 100644 --- a/Lib/venv/scripts/posix/activate.fish +++ b/Lib/venv/scripts/posix/activate.fish @@ -37,6 +37,7 @@ set -gx VIRTUAL_ENV "__VENV_DIR__" set -gx _OLD_VIRTUAL_PATH $PATH set -gx PATH "$VIRTUAL_ENV/__VENV_BIN_NAME__" $PATH +set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" # Unset PYTHONHOME if set. if set -q PYTHONHOME @@ -65,5 +66,4 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" end set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" - set -gx VIRTUAL_ENV_PROMPT "__VENV_PROMPT__" end diff --git a/Misc/NEWS.d/next/Library/2023-07-11-12-34-04.gh-issue-89427.GOkCp9.rst b/Misc/NEWS.d/next/Library/2023-07-11-12-34-04.gh-issue-89427.GOkCp9.rst new file mode 100644 index 00000000000000..1605920cb8138b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-11-12-34-04.gh-issue-89427.GOkCp9.rst @@ -0,0 +1,2 @@ +Set the environment variable ``VIRTUAL_ENV_PROMPT`` at :mod:`venv` +activation, even when ``VIRTUAL_ENV_DISABLE_PROMPT`` is set. From 7e6ce48872fa3de98c986057764f35e1b2f4b936 Mon Sep 17 00:00:00 2001 From: CF Bolz-Tereick Date: Thu, 13 Jul 2023 08:12:56 +0200 Subject: [PATCH 379/446] gh-106628: email parsing speedup (gh-106629) --- Lib/email/feedparser.py | 15 +++++++++------ ...2023-07-11-16-36-22.gh-issue-106628.Kx8Zvc.rst | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-11-16-36-22.gh-issue-106628.Kx8Zvc.rst diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 885097c7dda067..53d71f50225152 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -37,6 +37,8 @@ headerRE = re.compile(r'^(From |[\041-\071\073-\176]*:|[\t ])') EMPTYSTRING = '' NL = '\n' +boundaryendRE = re.compile( + r'(?P--)?(?P[ \t]*)(?P\r\n|\r|\n)?$') NeedMoreData = object() @@ -327,9 +329,10 @@ def _parsegen(self): # this onto the input stream until we've scanned past the # preamble. separator = '--' + boundary - boundaryre = re.compile( - '(?P' + re.escape(separator) + - r')(?P--)?(?P[ \t]*)(?P\r\n|\r|\n)?$') + def boundarymatch(line): + if not line.startswith(separator): + return None + return boundaryendRE.match(line, len(separator)) capturing_preamble = True preamble = [] linesep = False @@ -341,7 +344,7 @@ def _parsegen(self): continue if line == '': break - mo = boundaryre.match(line) + mo = boundarymatch(line) if mo: # If we're looking at the end boundary, we're done with # this multipart. If there was a newline at the end of @@ -373,13 +376,13 @@ def _parsegen(self): if line is NeedMoreData: yield NeedMoreData continue - mo = boundaryre.match(line) + mo = boundarymatch(line) if not mo: self._input.unreadline(line) break # Recurse to parse this subpart; the input stream points # at the subpart's first line. - self._input.push_eof_matcher(boundaryre.match) + self._input.push_eof_matcher(boundarymatch) for retval in self._parsegen(): if retval is NeedMoreData: yield NeedMoreData diff --git a/Misc/NEWS.d/next/Library/2023-07-11-16-36-22.gh-issue-106628.Kx8Zvc.rst b/Misc/NEWS.d/next/Library/2023-07-11-16-36-22.gh-issue-106628.Kx8Zvc.rst new file mode 100644 index 00000000000000..6fa276e901f648 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-11-16-36-22.gh-issue-106628.Kx8Zvc.rst @@ -0,0 +1,2 @@ +Speed up parsing of emails by about 20% by not compiling a new regular +expression for every single email. From 4b4a5b70aa8d47b1e2a0582b741c31b786da762a Mon Sep 17 00:00:00 2001 From: Chris Brett Date: Thu, 13 Jul 2023 08:51:13 +0100 Subject: [PATCH 380/446] gh-106634: Corrected minor asyncio doc issues (#106671) --- Lib/asyncio/base_events.py | 2 +- Lib/asyncio/events.py | 2 +- Misc/ACKS | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index f650e6b0488cf8..b092c9343634e2 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -727,7 +727,7 @@ def call_later(self, delay, callback, *args, context=None): always relative to the current time. Each callback will be called exactly once. If two callbacks - are scheduled for exactly the same time, it undefined which + are scheduled for exactly the same time, it is undefined which will be called first. Any positional arguments after the callback will be passed to diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index ce44942186b272..0ccf85105e6673 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -617,7 +617,7 @@ class AbstractEventLoopPolicy: def get_event_loop(self): """Get the event loop for the current context. - Returns an event loop object implementing the BaseEventLoop interface, + Returns an event loop object implementing the AbstractEventLoop interface, or raises an exception in case no event loop has been set for the current context and the current policy does not specify to create one. diff --git a/Misc/ACKS b/Misc/ACKS index ef0029a7e4119d..645ad5b700baaa 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -226,6 +226,7 @@ Erik Bray Brian Brazil Demian Brecht Dave Brennan +Christopher Richard James Brett Tom Bridgman Anthony Briggs Keith Briggs From 32718f908cc92c474fd968912368b8a4500bd055 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 13 Jul 2023 14:30:35 +0100 Subject: [PATCH 381/446] gh-106309: Deprecate typing.no_type_check_decorator (#106312) --- Doc/library/typing.rst | 35 +++++++++++-------- Doc/whatsnew/3.13.rst | 4 +++ Lib/test/test_typing.py | 12 ++++--- Lib/typing.py | 2 ++ ...-07-01-16-51-55.gh-issue-106309.hSlB17.rst | 2 ++ 5 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-01-16-51-55.gh-issue-106309.hSlB17.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 11af3ea3c9030a..0cf875582f7f42 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -2849,6 +2849,9 @@ Functions and decorators This wraps the decorator with something that wraps the decorated function in :func:`no_type_check`. + .. deprecated-removed:: 3.13 3.15 + No type checker ever added support for ``@no_type_check_decorator``. It + is therefore deprecated, and will be removed in Python 3.15. .. decorator:: override @@ -3648,18 +3651,20 @@ Certain features in ``typing`` are deprecated and may be removed in a future version of Python. The following table summarizes major deprecations for your convenience. This is subject to change, and not all deprecations are listed. -+----------------------------------+---------------+-------------------+----------------+ -| Feature | Deprecated in | Projected removal | PEP/issue | -+==================================+===============+===================+================+ -| ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | -| collections | | | | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | -| ``typing.Sized`` | | | | -+----------------------------------+---------------+-------------------+----------------+ -| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` | -+----------------------------------+---------------+-------------------+----------------+ ++-------------------------------------+---------------+-------------------+----------------+ +| Feature | Deprecated in | Projected removal | PEP/issue | ++=====================================+===============+===================+================+ +| ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | +| collections | | | | ++-------------------------------------+---------------+-------------------+----------------+ +| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | ++-------------------------------------+---------------+-------------------+----------------+ +| ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | ++-------------------------------------+---------------+-------------------+----------------+ +| ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | +| ``typing.Sized`` | | | | ++-------------------------------------+---------------+-------------------+----------------+ +| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` | ++-------------------------------------+---------------+-------------------+----------------+ +| ``typing.no_type_check_decorator`` | 3.13 | 3.15 | :gh:`106309` | ++-------------------------------------+---------------+-------------------+----------------+ diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index b7c436fc151611..06fcaf4608cdcb 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -161,6 +161,10 @@ Deprecated ``NT = NamedTuple("NT", [])``. To create a TypedDict class with 0 fields, use ``class TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``. (Contributed by Alex Waygood in :gh:`105566` and :gh:`105570`.) +* :func:`typing.no_type_check_decorator` is deprecated, and scheduled for + removal in Python 3.15. After eight years in the :mod:`typing` module, it + has yet to be supported by any major type checkers. + (Contributed by Alex Waygood in :gh:`106309`.) * :mod:`array`'s ``'u'`` format code, deprecated in docs since Python 3.3, emits :exc:`DeprecationWarning` since 3.13 diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 1df21926d1f67e..0450a87577ecea 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -5794,10 +5794,14 @@ class F: get_type_hints(clazz) def test_meta_no_type_check(self): - - @no_type_check_decorator - def magic_decorator(func): - return func + depr_msg = ( + "'typing.no_type_check_decorator' is deprecated " + "and slated for removal in Python 3.15" + ) + with self.assertWarnsRegex(DeprecationWarning, depr_msg): + @no_type_check_decorator + def magic_decorator(func): + return func self.assertEqual(magic_decorator.__name__, 'magic_decorator') diff --git a/Lib/typing.py b/Lib/typing.py index 9187b74b0e2e1f..387b4c5ad5284b 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -2395,6 +2395,8 @@ def no_type_check_decorator(decorator): This wraps the decorator with something that wraps the decorated function in @no_type_check. """ + import warnings + warnings._deprecated("typing.no_type_check_decorator", remove=(3, 15)) @functools.wraps(decorator) def wrapped_decorator(*args, **kwds): func = decorator(*args, **kwds) diff --git a/Misc/NEWS.d/next/Library/2023-07-01-16-51-55.gh-issue-106309.hSlB17.rst b/Misc/NEWS.d/next/Library/2023-07-01-16-51-55.gh-issue-106309.hSlB17.rst new file mode 100644 index 00000000000000..5bd3880520871f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-01-16-51-55.gh-issue-106309.hSlB17.rst @@ -0,0 +1,2 @@ +Deprecate :func:`typing.no_type_check_decorator`. No major type checker ever +added support for this decorator. Patch by Alex Waygood. From 487861c6aef2fbcd92ccabb05ea1b57d18299b29 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 13 Jul 2023 16:36:19 +0100 Subject: [PATCH 382/446] GH-104909: Split `LOAD_ATTR_INSTANCE_VALUE` into micro-ops (GH-106678) --- Include/internal/pycore_opcode_metadata.h | 22 ++++--- ...-07-12-11-18-55.gh-issue-104909.DRUsuh.rst | 1 + Python/bytecodes.c | 19 +++++- Python/executor_cases.c.h | 18 ++++++ Python/generated_cases.c.h | 59 ++++++++++++------- Tools/cases_generator/generate_cases.py | 14 +---- 6 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-12-11-18-55.gh-issue-104909.DRUsuh.rst diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d2c1f9ad6e5fb3..79bbe9a916f596 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -39,10 +39,12 @@ #define _SKIP_CACHE 317 #define _GUARD_GLOBALS_VERSION 318 #define _GUARD_BUILTINS_VERSION 319 -#define IS_NONE 320 -#define _ITER_CHECK_RANGE 321 -#define _ITER_EXHAUSTED_RANGE 322 -#define _ITER_NEXT_RANGE 323 +#define _GUARD_TYPE_VERSION 320 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 321 +#define IS_NONE 322 +#define _ITER_CHECK_RANGE 323 +#define _ITER_EXHAUSTED_RANGE 324 +#define _ITER_NEXT_RANGE 325 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -932,7 +934,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC00, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC0, INSTR_FMT_IXC00, INSTR_FMT_IXC000 }; #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) @@ -1321,9 +1323,11 @@ const char * const _PyOpcode_uop_name[512] = { [317] = "_SKIP_CACHE", [318] = "_GUARD_GLOBALS_VERSION", [319] = "_GUARD_BUILTINS_VERSION", - [320] = "IS_NONE", - [321] = "_ITER_CHECK_RANGE", - [322] = "_ITER_EXHAUSTED_RANGE", - [323] = "_ITER_NEXT_RANGE", + [320] = "_GUARD_TYPE_VERSION", + [321] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", + [322] = "IS_NONE", + [323] = "_ITER_CHECK_RANGE", + [324] = "_ITER_EXHAUSTED_RANGE", + [325] = "_ITER_NEXT_RANGE", }; #endif // NEED_OPCODE_METADATA diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-12-11-18-55.gh-issue-104909.DRUsuh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-12-11-18-55.gh-issue-104909.DRUsuh.rst new file mode 100644 index 00000000000000..e0c1e67515a62c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-12-11-18-55.gh-issue-104909.DRUsuh.rst @@ -0,0 +1 @@ +Split :opcode:`LOAD_ATTR_INSTANCE_VALUE` into micro-ops. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 18862f87b65fa0..176dbb584d0987 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1816,14 +1816,21 @@ dummy_func( LOAD_ATTR, }; - inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - assert(tp->tp_dictoffset < 0); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + } + + op(_CHECK_MANAGED_OBJECT_HAS_VALUES, (owner -- owner)) { + assert(Py_TYPE(owner)->tp_dictoffset < 0); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + } + + op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); res = _PyDictOrValues_GetValues(dorv)->values[index]; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); @@ -1832,6 +1839,12 @@ dummy_func( DECREF_INPUTS(); } + macro(LOAD_ATTR_INSTANCE_VALUE) = + _SKIP_CACHE + // Skip over the counter + _GUARD_TYPE_VERSION + + _CHECK_MANAGED_OBJECT_HAS_VALUES + + _LOAD_ATTR_INSTANCE_VALUE; + inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 2c2dbf429cec11..805ea06e072167 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1425,6 +1425,24 @@ break; } + case _GUARD_TYPE_VERSION: { + PyObject *owner = stack_pointer[-1]; + uint32_t type_version = (uint32_t)operand; + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + break; + } + + case _CHECK_MANAGED_OBJECT_HAS_VALUES: { + PyObject *owner = stack_pointer[-1]; + assert(Py_TYPE(owner)->tp_dictoffset < 0); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + break; + } + case COMPARE_OP: { static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 383432f51a89ac..d43c7386bd6f6d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2240,28 +2240,45 @@ } TARGET(LOAD_ATTR_INSTANCE_VALUE) { - PyObject *owner = stack_pointer[-1]; - PyObject *res2 = NULL; - PyObject *res; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - assert(tp->tp_dictoffset < 0); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - res = _PyDictOrValues_GetValues(dorv)->values[index]; - DEOPT_IF(res == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; - Py_DECREF(owner); - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1] = res; - if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + PyObject *_tmp_1; + PyObject *_tmp_2 = stack_pointer[-1]; + { + } + { + PyObject *owner = _tmp_2; + uint32_t type_version = read_u32(&next_instr[1].cache); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + _tmp_2 = owner; + } + { + PyObject *owner = _tmp_2; + assert(Py_TYPE(owner)->tp_dictoffset < 0); + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + _tmp_2 = owner; + } + { + PyObject *owner = _tmp_2; + PyObject *res2 = NULL; + PyObject *res; + uint16_t index = read_u16(&next_instr[3].cache); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + res = _PyDictOrValues_GetValues(dorv)->values[index]; + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + res2 = NULL; + Py_DECREF(owner); + if (oparg & 1) { _tmp_2 = res2; } + _tmp_1 = res; + } next_instr += 9; + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = _tmp_1; + if (oparg & 1) { stack_pointer[-2] = _tmp_2; } DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a20abcde85b7c7..ba4ef1ee97693e 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -839,19 +839,7 @@ def map_families(self) -> None: ) else: member_instr.family = family - elif member_macro := self.macro_instrs.get(member): - for part in member_macro.parts: - if isinstance(part, Component): - if part.instr.family not in (family, None): - self.error( - f"Component {part.instr.name} of macro {member} " - f"is a member of multiple families " - f"({part.instr.family.name}, {family.name}).", - family, - ) - else: - part.instr.family = family - else: + elif not self.macro_instrs.get(member): self.error( f"Unknown instruction {member!r} referenced in family {family.name!r}", family, From 2f3ee02c22c4b42bf6075a75104c3cfbb4eb4c86 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Thu, 13 Jul 2023 11:45:21 -0400 Subject: [PATCH 383/446] gh-106690: Add a .coveragerc file to the CPython repository (#8150) The added file is the coverage default at some point in time + checking branches both ways + IDLE additions, labelled as such and somewhat designed to be unlikely to affect other files. Located in the CPython repository directory, it can be used where it is or copied elsewhere, depending on how one runs coverage. --------- Co-authored-by: Terry Jan Reedy Co-authored-by: Alex Waygood Co-authored-by: Erlend E. Aasland --- .coveragerc | 19 +++++++++++++++++++ ...-07-12-14-07-07.gh-issue-106690.NDz-oG.rst | 1 + 2 files changed, 20 insertions(+) create mode 100644 .coveragerc create mode 100644 Misc/NEWS.d/next/Tests/2023-07-12-14-07-07.gh-issue-106690.NDz-oG.rst diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000000000..18bf2f40fe523f --- /dev/null +++ b/.coveragerc @@ -0,0 +1,19 @@ +[run] +branch = True + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + + .*# pragma: no cover + .*# pragma: no branch + + # Additions for IDLE: + .*# htest # + if not (_htest or _utest): + if not .*_utest: + if .*_htest: + diff --git a/Misc/NEWS.d/next/Tests/2023-07-12-14-07-07.gh-issue-106690.NDz-oG.rst b/Misc/NEWS.d/next/Tests/2023-07-12-14-07-07.gh-issue-106690.NDz-oG.rst new file mode 100644 index 00000000000000..e7dc0ac2220502 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-12-14-07-07.gh-issue-106690.NDz-oG.rst @@ -0,0 +1 @@ +Add .coveragerc to cpython repository for use with coverage package. From e6e0ea0113748db1e9fe675be6db9041cd5cce1f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 13 Jul 2023 12:14:51 -0700 Subject: [PATCH 384/446] gh-106701: Move the hand-written Tier 2 uops to bytecodes.c (#106702) This moves EXIT_TRACE, SAVE_IP, JUMP_TO_TOP, and _POP_JUMP_IF_{FALSE,TRUE} from ceval.c to bytecodes.c. They are no less special than before, but this way they are discoverable o the copy-and-patch tooling. --- Include/internal/pycore_opcode_metadata.h | 100 +++++++++++----------- Python/bytecodes.c | 30 +++++++ Python/ceval.c | 40 --------- Python/executor_cases.c.h | 36 ++++++++ Tools/cases_generator/generate_cases.py | 12 ++- 5 files changed, 124 insertions(+), 94 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 79bbe9a916f596..c88640777e3fb0 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -21,30 +21,30 @@ #define EXIT_TRACE 300 #define SAVE_IP 301 -#define _POP_JUMP_IF_FALSE 302 -#define _POP_JUMP_IF_TRUE 303 -#define JUMP_TO_TOP 304 -#define _GUARD_BOTH_INT 305 -#define _BINARY_OP_MULTIPLY_INT 306 -#define _BINARY_OP_ADD_INT 307 -#define _BINARY_OP_SUBTRACT_INT 308 -#define _GUARD_BOTH_FLOAT 309 -#define _BINARY_OP_MULTIPLY_FLOAT 310 -#define _BINARY_OP_ADD_FLOAT 311 -#define _BINARY_OP_SUBTRACT_FLOAT 312 -#define _GUARD_BOTH_UNICODE 313 -#define _BINARY_OP_ADD_UNICODE 314 -#define _LOAD_LOCALS 315 -#define _LOAD_FROM_DICT_OR_GLOBALS 316 -#define _SKIP_CACHE 317 -#define _GUARD_GLOBALS_VERSION 318 -#define _GUARD_BUILTINS_VERSION 319 -#define _GUARD_TYPE_VERSION 320 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 321 -#define IS_NONE 322 -#define _ITER_CHECK_RANGE 323 -#define _ITER_EXHAUSTED_RANGE 324 -#define _ITER_NEXT_RANGE 325 +#define _GUARD_BOTH_INT 302 +#define _BINARY_OP_MULTIPLY_INT 303 +#define _BINARY_OP_ADD_INT 304 +#define _BINARY_OP_SUBTRACT_INT 305 +#define _GUARD_BOTH_FLOAT 306 +#define _BINARY_OP_MULTIPLY_FLOAT 307 +#define _BINARY_OP_ADD_FLOAT 308 +#define _BINARY_OP_SUBTRACT_FLOAT 309 +#define _GUARD_BOTH_UNICODE 310 +#define _BINARY_OP_ADD_UNICODE 311 +#define _LOAD_LOCALS 312 +#define _LOAD_FROM_DICT_OR_GLOBALS 313 +#define _SKIP_CACHE 314 +#define _GUARD_GLOBALS_VERSION 315 +#define _GUARD_BUILTINS_VERSION 316 +#define _GUARD_TYPE_VERSION 317 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 318 +#define IS_NONE 319 +#define _ITER_CHECK_RANGE 320 +#define _ITER_EXHAUSTED_RANGE 321 +#define _ITER_NEXT_RANGE 322 +#define _POP_JUMP_IF_FALSE 323 +#define _POP_JUMP_IF_TRUE 324 +#define JUMP_TO_TOP 325 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1303,31 +1303,31 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; const char * const _PyOpcode_uop_name[512] = { - [300] = "EXIT_TRACE", - [301] = "SAVE_IP", - [302] = "_POP_JUMP_IF_FALSE", - [303] = "_POP_JUMP_IF_TRUE", - [304] = "JUMP_TO_TOP", - [305] = "_GUARD_BOTH_INT", - [306] = "_BINARY_OP_MULTIPLY_INT", - [307] = "_BINARY_OP_ADD_INT", - [308] = "_BINARY_OP_SUBTRACT_INT", - [309] = "_GUARD_BOTH_FLOAT", - [310] = "_BINARY_OP_MULTIPLY_FLOAT", - [311] = "_BINARY_OP_ADD_FLOAT", - [312] = "_BINARY_OP_SUBTRACT_FLOAT", - [313] = "_GUARD_BOTH_UNICODE", - [314] = "_BINARY_OP_ADD_UNICODE", - [315] = "_LOAD_LOCALS", - [316] = "_LOAD_FROM_DICT_OR_GLOBALS", - [317] = "_SKIP_CACHE", - [318] = "_GUARD_GLOBALS_VERSION", - [319] = "_GUARD_BUILTINS_VERSION", - [320] = "_GUARD_TYPE_VERSION", - [321] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", - [322] = "IS_NONE", - [323] = "_ITER_CHECK_RANGE", - [324] = "_ITER_EXHAUSTED_RANGE", - [325] = "_ITER_NEXT_RANGE", + [EXIT_TRACE] = "EXIT_TRACE", + [SAVE_IP] = "SAVE_IP", + [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", + [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", + [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", + [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT", + [_GUARD_BOTH_FLOAT] = "_GUARD_BOTH_FLOAT", + [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", + [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", + [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", + [_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE", + [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", + [_LOAD_LOCALS] = "_LOAD_LOCALS", + [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS", + [_SKIP_CACHE] = "_SKIP_CACHE", + [_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION", + [_GUARD_BUILTINS_VERSION] = "_GUARD_BUILTINS_VERSION", + [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", + [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", + [IS_NONE] = "IS_NONE", + [_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE", + [_ITER_EXHAUSTED_RANGE] = "_ITER_EXHAUSTED_RANGE", + [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", + [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE", + [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE", + [JUMP_TO_TOP] = "JUMP_TO_TOP", }; #endif // NEED_OPCODE_METADATA diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 176dbb584d0987..1fe9970e53cdfe 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3654,6 +3654,36 @@ dummy_func( Py_UNREACHABLE(); } + ///////// Tier-2 only opcodes ///////// + + op(_POP_JUMP_IF_FALSE, (flag -- )) { + if (Py_IsFalse(flag)) { + pc = oparg; + } + } + + op(_POP_JUMP_IF_TRUE, (flag -- )) { + if (Py_IsTrue(flag)) { + pc = oparg; + } + } + + op(JUMP_TO_TOP, (--)) { + pc = 0; + CHECK_EVAL_BREAKER(); + } + + op(SAVE_IP, (--)) { + frame->prev_instr = ip_offset + oparg; + } + + op(EXIT_TRACE, (--)) { + frame->prev_instr--; // Back up to just before destination + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(self); + return frame; + } + // END BYTECODES // diff --git a/Python/ceval.c b/Python/ceval.c index de44085d732cfa..d6c72fa3ff386c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2764,46 +2764,6 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject #define ENABLE_SPECIALIZATION 0 #include "executor_cases.c.h" - // NOTE: These pop-jumps move the uop pc, not the bytecode ip - case _POP_JUMP_IF_FALSE: - { - if (Py_IsFalse(stack_pointer[-1])) { - pc = oparg; - } - stack_pointer--; - break; - } - - case _POP_JUMP_IF_TRUE: - { - if (Py_IsTrue(stack_pointer[-1])) { - pc = oparg; - } - stack_pointer--; - break; - } - - case JUMP_TO_TOP: - { - pc = 0; - CHECK_EVAL_BREAKER(); - break; - } - - case SAVE_IP: - { - frame->prev_instr = ip_offset + oparg; - break; - } - - case EXIT_TRACE: - { - frame->prev_instr--; // Back up to just before destination - _PyFrame_SetStackPointer(frame, stack_pointer); - Py_DECREF(self); - return frame; - } - default: { fprintf(stderr, "Unknown uop %d, operand %" PRIu64 "\n", opcode, operand); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 805ea06e072167..ce54755d5d25f1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1987,3 +1987,39 @@ stack_pointer[-(2 + (oparg-2))] = top; break; } + + case _POP_JUMP_IF_FALSE: { + PyObject *flag = stack_pointer[-1]; + if (Py_IsFalse(flag)) { + pc = oparg; + } + STACK_SHRINK(1); + break; + } + + case _POP_JUMP_IF_TRUE: { + PyObject *flag = stack_pointer[-1]; + if (Py_IsTrue(flag)) { + pc = oparg; + } + STACK_SHRINK(1); + break; + } + + case JUMP_TO_TOP: { + pc = 0; + break; + } + + case SAVE_IP: { + frame->prev_instr = ip_offset + oparg; + break; + } + + case EXIT_TRACE: { + frame->prev_instr--; // Back up to just before destination + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(self); + return frame; + break; + } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ba4ef1ee97693e..ce16271097b955 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -410,6 +410,8 @@ def __init__(self, inst: parser.InstDef): def is_viable_uop(self) -> bool: """Whether this instruction is viable as a uop.""" + if self.name == "EXIT_TRACE": + return True # This has 'return frame' but it's okay if self.always_exits: # print(f"Skipping {self.name} because it always exits") return False @@ -1278,7 +1280,7 @@ def write_metadata(self) -> None: typing.assert_never(thing) with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): - self.write_uop_items(lambda name, counter: f"[{counter}] = \"{name}\",") + self.write_uop_items(lambda name, counter: f"[{name}] = \"{name}\",") self.out.emit("#endif // NEED_OPCODE_METADATA") @@ -1324,17 +1326,19 @@ def write_pseudo_instrs(self) -> None: def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None: """Write '#define XXX NNN' for each uop""" counter = 300 # TODO: Avoid collision with pseudo instructions + seen = set() def add(name: str) -> None: + if name in seen: + return nonlocal counter self.out.emit(make_text(name, counter)) counter += 1 + seen.add(name) + # These two are first by convention add("EXIT_TRACE") add("SAVE_IP") - add("_POP_JUMP_IF_FALSE") - add("_POP_JUMP_IF_TRUE") - add("JUMP_TO_TOP") for instr in self.instrs.values(): if instr.kind == "op" and instr.is_viable_uop(): From 8d2f3c36caf9ecdee1176314b18388aef6e7f2c2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 13 Jul 2023 09:18:53 -1000 Subject: [PATCH 385/446] gh-106664: selectors: add get() method to _SelectorMapping (#106665) It can be used to avoid raising and catching KeyError twice via __getitem__. Co-authored-by: Inada Naoki --- Lib/selectors.py | 14 +++++++++----- Lib/test/test_selectors.py | 6 ++++++ .../2023-07-12-03-04-45.gh-issue-106664.ZeUG78.rst | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-12-03-04-45.gh-issue-106664.ZeUG78.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index af6a4f94b5008a..dfcc125dcd94ef 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -66,12 +66,16 @@ def __init__(self, selector): def __len__(self): return len(self._selector._fd_to_key) + def get(self, fileobj, default=None): + fd = self._selector._fileobj_lookup(fileobj) + return self._selector._fd_to_key.get(fd, default) + def __getitem__(self, fileobj): - try: - fd = self._selector._fileobj_lookup(fileobj) - return self._selector._fd_to_key[fd] - except KeyError: - raise KeyError("{!r} is not registered".format(fileobj)) from None + fd = self._selector._fileobj_lookup(fileobj) + key = self._selector._fd_to_key.get(fd) + if key is None: + raise KeyError("{!r} is not registered".format(fileobj)) + return key def __iter__(self): return iter(self._selector._fd_to_key) diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index c2db88c203920a..4545cbadb796fd 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -223,6 +223,8 @@ def test_close(self): self.assertRaises(RuntimeError, s.get_key, wr) self.assertRaises(KeyError, mapping.__getitem__, rd) self.assertRaises(KeyError, mapping.__getitem__, wr) + self.assertEqual(mapping.get(rd), None) + self.assertEqual(mapping.get(wr), None) def test_get_key(self): s = self.SELECTOR() @@ -241,13 +243,17 @@ def test_get_map(self): self.addCleanup(s.close) rd, wr = self.make_socketpair() + sentinel = object() keys = s.get_map() self.assertFalse(keys) self.assertEqual(len(keys), 0) self.assertEqual(list(keys), []) + self.assertEqual(keys.get(rd), None) + self.assertEqual(keys.get(rd, sentinel), sentinel) key = s.register(rd, selectors.EVENT_READ, "data") self.assertIn(rd, keys) + self.assertEqual(key, keys.get(rd)) self.assertEqual(key, keys[rd]) self.assertEqual(len(keys), 1) self.assertEqual(list(keys), [rd.fileno()]) diff --git a/Misc/NEWS.d/next/Library/2023-07-12-03-04-45.gh-issue-106664.ZeUG78.rst b/Misc/NEWS.d/next/Library/2023-07-12-03-04-45.gh-issue-106664.ZeUG78.rst new file mode 100644 index 00000000000000..c278cad74bd049 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-12-03-04-45.gh-issue-106664.ZeUG78.rst @@ -0,0 +1 @@ +:mod:`selectors`: Add ``_SelectorMapping.get()`` method and optimize ``_SelectorMapping.__getitem__()``. From f014f1567c081542aaf5cecce118edf35e09bcc5 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 13 Jul 2023 12:24:54 -0700 Subject: [PATCH 386/446] docs: clarify Path.suffix (GH-106650) --- Doc/library/pathlib.rst | 5 +++-- Doc/library/zipfile.rst | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 338575404ff0ad..af81df217eea92 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -432,7 +432,7 @@ Pure paths provide the following methods and properties: .. attribute:: PurePath.suffix - The file extension of the final component, if any:: + The last dot-separated portion of the final component, if any:: >>> PurePosixPath('my/library/setup.py').suffix '.py' @@ -441,10 +441,11 @@ Pure paths provide the following methods and properties: >>> PurePosixPath('my/library').suffix '' + This is commonly called the file extension. .. attribute:: PurePath.suffixes - A list of the path's file extensions:: + A list of the path's suffixes, often called file extensions:: >>> PurePosixPath('my/library.tar.gar').suffixes ['.tar', '.gar'] diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 45f3d340bd82d3..bd951e4872f113 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -577,7 +577,8 @@ Path objects are traversable using the ``/`` operator or ``joinpath``. .. data:: Path.suffix - The file extension of the final component. + The last dot-separated portion of the final component, if any. + This is commonly called the file extension. .. versionadded:: 3.11 Added :data:`Path.suffix` property. @@ -591,7 +592,7 @@ Path objects are traversable using the ``/`` operator or ``joinpath``. .. data:: Path.suffixes - A list of the path’s file extensions. + A list of the path’s suffixes, commonly called file extensions. .. versionadded:: 3.11 Added :data:`Path.suffixes` property. From ec45c513d389510930a62631a21a1dbb3f3aabb7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 14 Jul 2023 00:18:32 +0200 Subject: [PATCH 387/446] gh-106368: Increase Argument Clinic test coverage (#106728) - improve output_parameter() coverage - improve coverage for Function.kind --- Lib/test/clinic.test.c | 553 ++++++++++++++++++++++++++++++++++++++++ Lib/test/test_clinic.py | 37 +++ 2 files changed, 590 insertions(+) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index da97c4bdd7e8e5..2fd8760415dc72 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -3,6 +3,10 @@ output preset block [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=3c81ac2402d06a8b]*/ +/*[clinic input] +class Test "TestObj *" "TestType" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=fc7e50384d12b83f]*/ /*[clinic input] test_object_converter @@ -61,6 +65,58 @@ test_object_converter_impl(PyObject *module, PyObject *a, PyObject *b, /*[clinic end generated code: output=886f4f9b598726b6 input=005e6a8a711a869b]*/ +/*[clinic input] +cloned = test_object_converter +Check the clone feature. +[clinic start generated code]*/ + +PyDoc_STRVAR(cloned__doc__, +"cloned($module, a, b, c, d, /)\n" +"--\n" +"\n" +"Check the clone feature."); + +#define CLONED_METHODDEF \ + {"cloned", _PyCFunction_CAST(cloned), METH_FASTCALL, cloned__doc__}, + +static PyObject * +cloned_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, + PyUnicode_Object *d); + +static PyObject * +cloned(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *a; + PyObject *b; + PyObject *c; + PyUnicode_Object *d; + + if (!_PyArg_CheckPositional("cloned", nargs, 4, 4)) { + goto exit; + } + a = args[0]; + if (!PyUnicode_FSConverter(args[1], &b)) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("cloned", "argument 3", "str", args[2]); + goto exit; + } + c = args[2]; + d = (PyUnicode_Object *)args[3]; + return_value = cloned_impl(module, a, b, c, d); + +exit: + return return_value; +} + +static PyObject * +cloned_impl(PyObject *module, PyObject *a, PyObject *b, PyObject *c, + PyUnicode_Object *d) +/*[clinic end generated code: output=026b483e27c38065 input=0543614019d6fcc7]*/ + + /*[clinic input] test_object_converter_one_arg @@ -4265,3 +4321,500 @@ static PyObject * mangle2_impl(PyObject *module, PyObject *args, PyObject *kwargs, PyObject *return_value) /*[clinic end generated code: output=2ebb62aaefe7590a input=391766fee51bad7a]*/ + + +/*[clinic input] +Test.cls_with_param + cls: defining_class + / + a: int +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_cls_with_param__doc__, +"cls_with_param($self, /, a)\n" +"--\n" +"\n"); + +#define TEST_CLS_WITH_PARAM_METHODDEF \ + {"cls_with_param", _PyCFunction_CAST(Test_cls_with_param), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, Test_cls_with_param__doc__}, + +static PyObject * +Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a); + +static PyObject * +Test_cls_with_param(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(a), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"a", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "cls_with_param", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int a; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + a = _PyLong_AsInt(args[0]); + if (a == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = Test_cls_with_param_impl(self, cls, a); + +exit: + return return_value; +} + +static PyObject * +Test_cls_with_param_impl(TestObj *self, PyTypeObject *cls, int a) +/*[clinic end generated code: output=00218e7f583e6c81 input=af158077bd237ef9]*/ + + +/*[clinic input] +Test.__init__ +Empty init method. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test()\n" +"--\n" +"\n" +"Empty init method."); + +static int +Test___init___impl(TestObj *self); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = TestType; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoPositional("Test", args)) { + goto exit; + } + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + return_value = Test___init___impl((TestObj *)self); + +exit: + return return_value; +} + +static int +Test___init___impl(TestObj *self) +/*[clinic end generated code: output=f6a35c85bc5b408f input=4ea79fee54d0c3ff]*/ + + +/*[clinic input] +@classmethod +Test.__new__ +Empty new method. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test__doc__, +"Test()\n" +"--\n" +"\n" +"Empty new method."); + +static PyObject * +Test_impl(PyTypeObject *type); + +static PyObject * +Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = TestType; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoPositional("Test", args)) { + goto exit; + } + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + return_value = Test_impl(type); + +exit: + return return_value; +} + +static PyObject * +Test_impl(PyTypeObject *type) +/*[clinic end generated code: output=68a117adc057940f input=6fe98a19f097907f]*/ + + +/*[clinic input] +Test.cls_no_params + cls: defining_class + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_cls_no_params__doc__, +"cls_no_params($self, /)\n" +"--\n" +"\n"); + +#define TEST_CLS_NO_PARAMS_METHODDEF \ + {"cls_no_params", _PyCFunction_CAST(Test_cls_no_params), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, Test_cls_no_params__doc__}, + +static PyObject * +Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls); + +static PyObject * +Test_cls_no_params(TestObj *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs) { + PyErr_SetString(PyExc_TypeError, "cls_no_params() takes no arguments"); + return NULL; + } + return Test_cls_no_params_impl(self, cls); +} + +static PyObject * +Test_cls_no_params_impl(TestObj *self, PyTypeObject *cls) +/*[clinic end generated code: output=cc8845f22cff3dcb input=e7e2e4e344e96a11]*/ + + +/*[clinic input] +Test.metho_not_default_return_converter -> int + a: object + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_metho_not_default_return_converter__doc__, +"metho_not_default_return_converter($self, a, /)\n" +"--\n" +"\n"); + +#define TEST_METHO_NOT_DEFAULT_RETURN_CONVERTER_METHODDEF \ + {"metho_not_default_return_converter", (PyCFunction)Test_metho_not_default_return_converter, METH_O, Test_metho_not_default_return_converter__doc__}, + +static int +Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a); + +static PyObject * +Test_metho_not_default_return_converter(TestObj *self, PyObject *a) +{ + PyObject *return_value = NULL; + int _return_value; + + _return_value = Test_metho_not_default_return_converter_impl(self, a); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +static int +Test_metho_not_default_return_converter_impl(TestObj *self, PyObject *a) +/*[clinic end generated code: output=3350de11bd538007 input=428657129b521177]*/ + + +/*[clinic input] +Test.an_metho_arg_named_arg + arg: int + Name should be mangled to 'arg_' in generated output. + / +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_an_metho_arg_named_arg__doc__, +"an_metho_arg_named_arg($self, arg, /)\n" +"--\n" +"\n" +"\n" +"\n" +" arg\n" +" Name should be mangled to \'arg_\' in generated output."); + +#define TEST_AN_METHO_ARG_NAMED_ARG_METHODDEF \ + {"an_metho_arg_named_arg", (PyCFunction)Test_an_metho_arg_named_arg, METH_O, Test_an_metho_arg_named_arg__doc__}, + +static PyObject * +Test_an_metho_arg_named_arg_impl(TestObj *self, int arg); + +static PyObject * +Test_an_metho_arg_named_arg(TestObj *self, PyObject *arg_) +{ + PyObject *return_value = NULL; + int arg; + + arg = _PyLong_AsInt(arg_); + if (arg == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = Test_an_metho_arg_named_arg_impl(self, arg); + +exit: + return return_value; +} + +static PyObject * +Test_an_metho_arg_named_arg_impl(TestObj *self, int arg) +/*[clinic end generated code: output=7d590626642194ae input=2a53a57cf5624f95]*/ + + +/*[clinic input] +Test.__init__ + *args: object + / +Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs init method. For example, nargs is translated to PyTuple_GET_SIZE."); + +static int +Test___init___impl(TestObj *self, PyObject *args); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((Py_IS_TYPE(self, base_tp) || + Py_TYPE(self)->tp_new == base_tp->tp_new) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { + goto exit; + } + __clinic_args = PyTuple_GetSlice(0, -1); + return_value = Test___init___impl((TestObj *)self, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +static int +Test___init___impl(TestObj *self, PyObject *args) +/*[clinic end generated code: output=0ed1009fe0dcf98d input=96c3ddc0cd38fc0c]*/ + + +/*[clinic input] +@classmethod +Test.__new__ + *args: object + / +Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test__doc__, +"Test(*args)\n" +"--\n" +"\n" +"Varargs new method. For example, nargs is translated to PyTuple_GET_SIZE."); + +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args); + +static PyObject * +Test(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyTypeObject *base_tp = TestType; + PyObject *__clinic_args = NULL; + + if ((type == base_tp || type->tp_init == base_tp->tp_init) && + !_PyArg_NoKeywords("Test", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("Test", PyTuple_GET_SIZE(args), 0, PY_SSIZE_T_MAX)) { + goto exit; + } + __clinic_args = PyTuple_GetSlice(0, -1); + return_value = Test_impl(type, __clinic_args); + +exit: + Py_XDECREF(__clinic_args); + return return_value; +} + +static PyObject * +Test_impl(PyTypeObject *type, PyObject *args) +/*[clinic end generated code: output=8b219f6633e2a2e9 input=26a672e2e9750120]*/ + + +/*[clinic input] +Test.__init__ + a: object +Init method with positional or keyword arguments. +[clinic start generated code]*/ + +PyDoc_STRVAR(Test___init____doc__, +"Test(a)\n" +"--\n" +"\n" +"Init method with positional or keyword arguments."); + +static int +Test___init___impl(TestObj *self, PyObject *a); + +static int +Test___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(a), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"a", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "Test", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *a; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + a = fastargs[0]; + return_value = Test___init___impl((TestObj *)self, a); + +exit: + return return_value; +} + +static int +Test___init___impl(TestObj *self, PyObject *a) +/*[clinic end generated code: output=0b9ca79638ab3ecb input=a8f9222a6ab35c59]*/ + + +/*[clinic input] +@classmethod +Test.class_method +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_class_method__doc__, +"class_method($type, /)\n" +"--\n" +"\n"); + +#define TEST_CLASS_METHOD_METHODDEF \ + {"class_method", (PyCFunction)Test_class_method, METH_NOARGS|METH_CLASS, Test_class_method__doc__}, + +static PyObject * +Test_class_method_impl(PyTypeObject *type); + +static PyObject * +Test_class_method(PyTypeObject *type, PyObject *Py_UNUSED(ignored)) +{ + return Test_class_method_impl(type); +} + +static PyObject * +Test_class_method_impl(PyTypeObject *type) +/*[clinic end generated code: output=47fb7ecca1abcaaa input=43bc4a0494547b80]*/ + + +/*[clinic input] +@staticmethod +Test.static_method +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_static_method__doc__, +"static_method()\n" +"--\n" +"\n"); + +#define TEST_STATIC_METHOD_METHODDEF \ + {"static_method", (PyCFunction)Test_static_method, METH_NOARGS|METH_STATIC, Test_static_method__doc__}, + +static PyObject * +Test_static_method_impl(); + +static PyObject * +Test_static_method(void *null, PyObject *Py_UNUSED(ignored)) +{ + return Test_static_method_impl(); +} + +static PyObject * +Test_static_method_impl() +/*[clinic end generated code: output=82524a63025cf7ab input=dae892fac55ae72b]*/ + + +/*[clinic input] +@coexist +Test.meth_coexist +[clinic start generated code]*/ + +PyDoc_STRVAR(Test_meth_coexist__doc__, +"meth_coexist($self, /)\n" +"--\n" +"\n"); + +#define TEST_METH_COEXIST_METHODDEF \ + {"meth_coexist", (PyCFunction)Test_meth_coexist, METH_NOARGS|METH_COEXIST, Test_meth_coexist__doc__}, + +static PyObject * +Test_meth_coexist_impl(TestObj *self); + +static PyObject * +Test_meth_coexist(TestObj *self, PyObject *Py_UNUSED(ignored)) +{ + return Test_meth_coexist_impl(self); +} + +static PyObject * +Test_meth_coexist_impl(TestObj *self) +/*[clinic end generated code: output=808a293d0cd27439 input=2a1d75b5e6fec6dd]*/ diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 685ba58642a5ae..975840333e5901 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1013,6 +1013,43 @@ def test_defining_class_param_cannot_be_optional(self): out = self.parse_function_should_fail(block) self.assertEqual(out, expected_error_msg) + def test_slot_methods_cannot_access_defining_class(self): + block = """ + module foo + class Foo "" "" + Foo.__init__ + cls: defining_class + a: object + """ + msg = "Slot methods cannot access their defining class." + with self.assertRaisesRegex(ValueError, msg): + self.parse_function(block) + + def test_new_must_be_a_class_method(self): + expected_error_msg = ( + "Error on line 0:\n" + "__new__ must be a class method!\n" + ) + out = self.parse_function_should_fail(""" + module foo + class Foo "" "" + Foo.__new__ + """) + self.assertEqual(out, expected_error_msg) + + def test_init_must_be_a_normal_method(self): + expected_error_msg = ( + "Error on line 0:\n" + "__init__ must be a normal method, not a class or static method!\n" + ) + out = self.parse_function_should_fail(""" + module foo + class Foo "" "" + @classmethod + Foo.__init__ + """) + self.assertEqual(out, expected_error_msg) + def test_unused_param(self): block = self.parse(""" module foo From 128a6c1d889639012c83c122b82c9cdf0b62d587 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 13 Jul 2023 23:54:05 +0100 Subject: [PATCH 388/446] gh-104683: Argument clinic: use an enum to describe the different kinds of functions (#106721) Argument clinic: use an enum to describe the different kinds of functions --- Tools/clinic/clinic.py | 69 +++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 8a75aba1e4de93..2dce33690993dd 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -807,7 +807,7 @@ def output_templates(self, f): default_return_converter = (not f.return_converter or f.return_converter.type == 'PyObject *') - new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + new_or_init = f.kind.new_or_init vararg = NO_VARARG pos_only = min_pos = max_pos = min_kw_only = pseudo_args = 0 @@ -1250,7 +1250,7 @@ def parser_body( if new_or_init: methoddef_define = '' - if f.kind == METHOD_NEW: + if f.kind is METHOD_NEW: parser_prototype = parser_prototype_keyword else: return_value_declaration = "int return_value = -1;" @@ -1475,7 +1475,7 @@ def render_function( last_group = 0 first_optional = len(selfless) positional = selfless and selfless[-1].is_positional_only() - new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + new_or_init = f.kind.new_or_init has_option_groups = False # offset i by -1 because first_optional needs to ignore self @@ -2441,9 +2441,28 @@ def __repr__(self) -> str: """.strip().split()) -INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW = """ -INVALID, CALLABLE, STATIC_METHOD, CLASS_METHOD, METHOD_INIT, METHOD_NEW -""".replace(",", "").strip().split() +class FunctionKind(enum.Enum): + INVALID = enum.auto() + CALLABLE = enum.auto() + STATIC_METHOD = enum.auto() + CLASS_METHOD = enum.auto() + METHOD_INIT = enum.auto() + METHOD_NEW = enum.auto() + + @functools.cached_property + def new_or_init(self) -> bool: + return self in {FunctionKind.METHOD_INIT, FunctionKind.METHOD_NEW} + + def __repr__(self) -> str: + return f"" + + +INVALID: Final = FunctionKind.INVALID +CALLABLE: Final = FunctionKind.CALLABLE +STATIC_METHOD: Final = FunctionKind.STATIC_METHOD +CLASS_METHOD: Final = FunctionKind.CLASS_METHOD +METHOD_INIT: Final = FunctionKind.METHOD_INIT +METHOD_NEW: Final = FunctionKind.METHOD_NEW ParamDict = dict[str, "Parameter"] ReturnConverterType = Callable[..., "CReturnConverter"] @@ -2471,7 +2490,7 @@ class Function: return_converter: CReturnConverter return_annotation: object = inspect.Signature.empty docstring: str = '' - kind: str = CALLABLE + kind: FunctionKind = CALLABLE coexist: bool = False # docstring_only means "don't generate a machine-readable # signature, just a normal docstring". it's True for @@ -2497,15 +2516,16 @@ def render_parameters(self) -> list[Parameter]: @property def methoddef_flags(self) -> str | None: - if self.kind in (METHOD_INIT, METHOD_NEW): + if self.kind.new_or_init: return None flags = [] - if self.kind == CLASS_METHOD: - flags.append('METH_CLASS') - elif self.kind == STATIC_METHOD: - flags.append('METH_STATIC') - else: - assert self.kind == CALLABLE, "unknown kind: " + repr(self.kind) + match self.kind: + case FunctionKind.CLASS_METHOD: + flags.append('METH_CLASS') + case FunctionKind.STATIC_METHOD: + flags.append('METH_STATIC') + case _ as kind: + assert kind is FunctionKind.CALLABLE, f"unknown kind: {kind!r}" if self.coexist: flags.append('METH_COEXIST') return '|'.join(flags) @@ -3888,7 +3908,7 @@ def correct_name_for_self( if f.cls: return "PyObject *", "self" return "PyObject *", "module" - if f.kind == STATIC_METHOD: + if f.kind is STATIC_METHOD: return "void *", "null" if f.kind in (CLASS_METHOD, METHOD_NEW): return "PyTypeObject *", "type" @@ -3921,9 +3941,8 @@ def pre_render(self): self.type = self.specified_type or self.type or default_type kind = self.function.kind - new_or_init = kind in (METHOD_NEW, METHOD_INIT) - if (kind == STATIC_METHOD) or new_or_init: + if kind is STATIC_METHOD or kind.new_or_init: self.show_in_signature = False # tp_new (METHOD_NEW) functions are of type newfunc: @@ -3973,7 +3992,7 @@ def render(self, parameter, data): parameter is a clinic.Parameter instance. data is a CRenderData instance. """ - if self.function.kind == STATIC_METHOD: + if self.function.kind is STATIC_METHOD: return self._render_self(parameter, data) @@ -3992,8 +4011,8 @@ def set_template_dict(self, template_dict): kind = self.function.kind cls = self.function.cls - if ((kind in (METHOD_NEW, METHOD_INIT)) and cls and cls.typedef): - if kind == METHOD_NEW: + if kind.new_or_init and cls and cls.typedef: + if kind is METHOD_NEW: type_check = ( '({0} == base_tp || {0}->tp_init == base_tp->tp_init)' ).format(self.name) @@ -4337,7 +4356,7 @@ class DSLParser: parameter_state: int seen_positional_with_default: bool indent: IndentStack - kind: str + kind: FunctionKind coexist: bool parameter_continuation: str preserve_output: bool @@ -4626,7 +4645,7 @@ def state_modulename_name(self, line: str | None) -> None: function_name = fields.pop() module, cls = self.clinic._module_and_class(fields) - if not (existing_function.kind == self.kind and existing_function.coexist == self.coexist): + if not (existing_function.kind is self.kind and existing_function.coexist == self.coexist): fail("'kind' of function and cloned function don't match! (@classmethod/@staticmethod/@coexist)") function = existing_function.copy( name=function_name, full_name=full_name, module=module, @@ -4679,11 +4698,11 @@ def state_modulename_name(self, line: str | None) -> None: fail(f"{fields[-1]} is a special method and cannot be converted to Argument Clinic! (Yet.)") if fields[-1] == '__new__': - if (self.kind != CLASS_METHOD) or (not cls): + if (self.kind is not CLASS_METHOD) or (not cls): fail("__new__ must be a class method!") self.kind = METHOD_NEW elif fields[-1] == '__init__': - if (self.kind != CALLABLE) or (not cls): + if (self.kind is not CALLABLE) or (not cls): fail("__init__ must be a normal method, not a class or static method!") self.kind = METHOD_INIT if not return_converter: @@ -5203,7 +5222,7 @@ def state_function_docstring(self, line): def format_docstring(self): f = self.function - new_or_init = f.kind in (METHOD_NEW, METHOD_INIT) + new_or_init = f.kind.new_or_init if new_or_init and not f.docstring: # don't render a docstring at all, no signature, nothing. return f.docstring From 025995feadaeebeef5d808f2564f0fd65b704ea5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 13 Jul 2023 17:27:35 -0700 Subject: [PATCH 389/446] gh-106529: Split FOR_ITER_{LIST,TUPLE} into uops (#106696) Also rename `_ITER_EXHAUSTED_XXX` to `_IS_ITER_EXHAUSTED_XXX` to make it clear this is a test. --- Include/internal/pycore_opcode_metadata.h | 26 +++-- Lib/test/test_capi/test_misc.py | 47 +++++++- Python/bytecodes.c | 129 ++++++++++++++++------ Python/executor_cases.c.h | 76 ++++++++++++- Python/generated_cases.c.h | 124 +++++++++++++-------- Python/optimizer.c | 87 +++++++++++---- 6 files changed, 378 insertions(+), 111 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index c88640777e3fb0..e94732b64384b5 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -39,12 +39,18 @@ #define _GUARD_TYPE_VERSION 317 #define _CHECK_MANAGED_OBJECT_HAS_VALUES 318 #define IS_NONE 319 -#define _ITER_CHECK_RANGE 320 -#define _ITER_EXHAUSTED_RANGE 321 -#define _ITER_NEXT_RANGE 322 -#define _POP_JUMP_IF_FALSE 323 -#define _POP_JUMP_IF_TRUE 324 -#define JUMP_TO_TOP 325 +#define _ITER_CHECK_LIST 320 +#define _IS_ITER_EXHAUSTED_LIST 321 +#define _ITER_NEXT_LIST 322 +#define _ITER_CHECK_TUPLE 323 +#define _IS_ITER_EXHAUSTED_TUPLE 324 +#define _ITER_NEXT_TUPLE 325 +#define _ITER_CHECK_RANGE 326 +#define _IS_ITER_EXHAUSTED_RANGE 327 +#define _ITER_NEXT_RANGE 328 +#define _POP_JUMP_IF_FALSE 329 +#define _POP_JUMP_IF_TRUE 330 +#define JUMP_TO_TOP 331 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1323,8 +1329,14 @@ const char * const _PyOpcode_uop_name[512] = { [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", [IS_NONE] = "IS_NONE", + [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", + [_IS_ITER_EXHAUSTED_LIST] = "_IS_ITER_EXHAUSTED_LIST", + [_ITER_NEXT_LIST] = "_ITER_NEXT_LIST", + [_ITER_CHECK_TUPLE] = "_ITER_CHECK_TUPLE", + [_IS_ITER_EXHAUSTED_TUPLE] = "_IS_ITER_EXHAUSTED_TUPLE", + [_ITER_NEXT_TUPLE] = "_ITER_NEXT_TUPLE", [_ITER_CHECK_RANGE] = "_ITER_CHECK_RANGE", - [_ITER_EXHAUSTED_RANGE] = "_ITER_EXHAUSTED_RANGE", + [_IS_ITER_EXHAUSTED_RANGE] = "_IS_ITER_EXHAUSTED_RANGE", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", [_POP_JUMP_IF_FALSE] = "_POP_JUMP_IF_FALSE", [_POP_JUMP_IF_TRUE] = "_POP_JUMP_IF_TRUE", diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index abdf7ed8976350..43c04463236a2a 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2590,7 +2590,6 @@ def testfunc(n): for i in range(n): total += i return total - # import dis; dis.dis(testfunc) opt = _testinternalcapi.get_uop_optimizer() with temporary_optimizer(opt): @@ -2602,7 +2601,51 @@ def testfunc(n): # for i, (opname, oparg) in enumerate(ex): # print(f"{i:4d}: {opname:<20s} {oparg:3d}") uops = {opname for opname, _ in ex} - self.assertIn("_ITER_EXHAUSTED_RANGE", uops) + self.assertIn("_IS_ITER_EXHAUSTED_RANGE", uops) + # Verification that the jump goes past END_FOR + # is done by manual inspection of the output + + def test_for_iter_list(self): + def testfunc(a): + total = 0 + for i in a: + total += i + return total + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + a = list(range(10)) + total = testfunc(a) + self.assertEqual(total, 45) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + # for i, (opname, oparg) in enumerate(ex): + # print(f"{i:4d}: {opname:<20s} {oparg:3d}") + uops = {opname for opname, _ in ex} + self.assertIn("_IS_ITER_EXHAUSTED_LIST", uops) + # Verification that the jump goes past END_FOR + # is done by manual inspection of the output + + def test_for_iter_tuple(self): + def testfunc(a): + total = 0 + for i in a: + total += i + return total + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + a = tuple(range(10)) + total = testfunc(a) + self.assertEqual(total, 45) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + # for i, (opname, oparg) in enumerate(ex): + # print(f"{i:4d}: {opname:<20s} {oparg:3d}") + uops = {opname for opname, _ in ex} + self.assertIn("_IS_ITER_EXHAUSTED_TUPLE", uops) # Verification that the jump goes past END_FOR # is done by manual inspection of the output diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1fe9970e53cdfe..15b48ae9d82672 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -17,6 +17,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES +#include "pycore_opcode_metadata.h" // uop names #include "pycore_opcode_utils.h" // MAKE_FUNCTION_* #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyInterpreterState_GET() @@ -55,13 +56,14 @@ static PyObject *value, *value1, *value2, *left, *right, *res, *sum, *prod, *sub; static PyObject *container, *start, *stop, *v, *lhs, *rhs, *res2; static PyObject *list, *tuple, *dict, *owner, *set, *str, *tup, *map, *keys; -static PyObject *exit_func, *lasti, *val, *retval, *obj, *iter; +static PyObject *exit_func, *lasti, *val, *retval, *obj, *iter, *exhausted; static PyObject *aiter, *awaitable, *iterable, *w, *exc_value, *bc, *locals; static PyObject *orig, *excs, *update, *b, *fromlist, *level, *from; static PyObject **pieces, **values; static size_t jump; // Dummy variables for cache effects static uint16_t invert, counter, index, hint; +#define unused 0 // Used in a macro def, can't be static static uint32_t type_version; static PyObject * @@ -2418,52 +2420,108 @@ dummy_func( INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); } - inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { + op(_ITER_CHECK_LIST, (iter -- iter)) { DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); + } + + op(_ITER_JUMP_LIST, (iter -- iter)) { _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); STAT_INC(FOR_ITER, hit); PyListObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyList_GET_SIZE(seq)) { - next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); - goto end_for_iter_list; // End of this instruction + if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + if (seq != NULL) { + it->it_seq = NULL; + Py_DECREF(seq); } - it->it_seq = NULL; - Py_DECREF(seq); + Py_DECREF(iter); + STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); + /* Jump forward oparg, then skip following END_FOR instruction */ + JUMPBY(oparg + 1); + DISPATCH(); } - Py_DECREF(iter); - STACK_SHRINK(1); - SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); - /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(oparg + 1); - DISPATCH(); - end_for_iter_list: - // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { + // Only used by Tier 2 + op(_IS_ITER_EXHAUSTED_LIST, (iter -- iter, exhausted)) { + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + exhausted = Py_True; + } + else { + exhausted = Py_False; + } + } + + op(_ITER_NEXT_LIST, (iter -- iter, next)) { + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyList_GET_SIZE(seq)); + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); + } + + macro(FOR_ITER_LIST) = + unused/1 + // Skip over the counter + _ITER_CHECK_LIST + + _ITER_JUMP_LIST + + _ITER_NEXT_LIST; + + op(_ITER_CHECK_TUPLE, (iter -- iter)) { + DEOPT_IF(Py_TYPE(iter) != &PyTupleIter_Type, FOR_ITER); + } + + op(_ITER_JUMP_TUPLE, (iter -- iter)) { _PyTupleIterObject *it = (_PyTupleIterObject *)iter; - DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); + assert(Py_TYPE(iter) == &PyTupleIter_Type); STAT_INC(FOR_ITER, hit); PyTupleObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyTuple_GET_SIZE(seq)) { - next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); - goto end_for_iter_tuple; // End of this instruction + if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + if (seq != NULL) { + it->it_seq = NULL; + Py_DECREF(seq); } - it->it_seq = NULL; - Py_DECREF(seq); + Py_DECREF(iter); + STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); + /* Jump forward oparg, then skip following END_FOR instruction */ + JUMPBY(oparg + 1); + DISPATCH(); } - Py_DECREF(iter); - STACK_SHRINK(1); - SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); - /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(oparg + 1); - DISPATCH(); - end_for_iter_tuple: - // Common case: no jump, leave it to the code generator } + // Only used by Tier 2 + op(_IS_ITER_EXHAUSTED_TUPLE, (iter -- iter, exhausted)) { + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + exhausted = Py_True; + } + else { + exhausted = Py_False; + } + } + + op(_ITER_NEXT_TUPLE, (iter -- iter, next)) { + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyTuple_GET_SIZE(seq)); + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); + } + + macro(FOR_ITER_TUPLE) = + unused/1 + // Skip over the counter + _ITER_CHECK_TUPLE + + _ITER_JUMP_TUPLE + + _ITER_NEXT_TUPLE; + op(_ITER_CHECK_RANGE, (iter -- iter)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -2484,7 +2542,7 @@ dummy_func( } // Only used by Tier 2 - op(_ITER_EXHAUSTED_RANGE, (iter -- iter, exhausted)) { + op(_IS_ITER_EXHAUSTED_RANGE, (iter -- iter, exhausted)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); exhausted = r->len <= 0 ? Py_True : Py_False; @@ -2502,7 +2560,10 @@ dummy_func( } macro(FOR_ITER_RANGE) = - unused/1 + _ITER_CHECK_RANGE + _ITER_JUMP_RANGE + _ITER_NEXT_RANGE; + unused/1 + // Skip over the counter + _ITER_CHECK_RANGE + + _ITER_JUMP_RANGE + + _ITER_NEXT_RANGE; inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ce54755d5d25f1..626baece814607 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1738,6 +1738,80 @@ break; } + case _ITER_CHECK_LIST: { + PyObject *iter = stack_pointer[-1]; + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); + break; + } + + case _IS_ITER_EXHAUSTED_LIST: { + PyObject *iter = stack_pointer[-1]; + PyObject *exhausted; + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + exhausted = Py_True; + } + else { + exhausted = Py_False; + } + STACK_GROW(1); + stack_pointer[-1] = exhausted; + break; + } + + case _ITER_NEXT_LIST: { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyList_GET_SIZE(seq)); + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); + STACK_GROW(1); + stack_pointer[-1] = next; + break; + } + + case _ITER_CHECK_TUPLE: { + PyObject *iter = stack_pointer[-1]; + DEOPT_IF(Py_TYPE(iter) != &PyTupleIter_Type, FOR_ITER); + break; + } + + case _IS_ITER_EXHAUSTED_TUPLE: { + PyObject *iter = stack_pointer[-1]; + PyObject *exhausted; + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + exhausted = Py_True; + } + else { + exhausted = Py_False; + } + STACK_GROW(1); + stack_pointer[-1] = exhausted; + break; + } + + case _ITER_NEXT_TUPLE: { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyTuple_GET_SIZE(seq)); + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); + STACK_GROW(1); + stack_pointer[-1] = next; + break; + } + case _ITER_CHECK_RANGE: { PyObject *iter = stack_pointer[-1]; _PyRangeIterObject *r = (_PyRangeIterObject *)iter; @@ -1745,7 +1819,7 @@ break; } - case _ITER_EXHAUSTED_RANGE: { + case _IS_ITER_EXHAUSTED_RANGE: { PyObject *iter = stack_pointer[-1]; PyObject *exhausted; _PyRangeIterObject *r = (_PyRangeIterObject *)iter; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d43c7386bd6f6d..68531dc074769e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3051,60 +3051,96 @@ } TARGET(FOR_ITER_LIST) { - PyObject *iter = stack_pointer[-1]; - PyObject *next; - DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); - _PyListIterObject *it = (_PyListIterObject *)iter; - STAT_INC(FOR_ITER, hit); - PyListObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyList_GET_SIZE(seq)) { - next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); - goto end_for_iter_list; // End of this instruction + PyObject *_tmp_1; + PyObject *_tmp_2 = stack_pointer[-1]; + { + PyObject *iter = _tmp_2; + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); + _tmp_2 = iter; + } + { + PyObject *iter = _tmp_2; + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + STAT_INC(FOR_ITER, hit); + PyListObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + if (seq != NULL) { + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); + /* Jump forward oparg, then skip following END_FOR instruction */ + JUMPBY(oparg + 1); + DISPATCH(); } - it->it_seq = NULL; - Py_DECREF(seq); + _tmp_2 = iter; + } + { + PyObject *iter = _tmp_2; + PyObject *next; + _PyListIterObject *it = (_PyListIterObject *)iter; + assert(Py_TYPE(iter) == &PyListIter_Type); + PyListObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyList_GET_SIZE(seq)); + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); + _tmp_2 = iter; + _tmp_1 = next; } - Py_DECREF(iter); - STACK_SHRINK(1); - SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); - /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(oparg + 1); - DISPATCH(); - end_for_iter_list: - // Common case: no jump, leave it to the code generator - STACK_GROW(1); - stack_pointer[-1] = next; next_instr += 1; + STACK_GROW(1); + stack_pointer[-1] = _tmp_1; + stack_pointer[-2] = _tmp_2; DISPATCH(); } TARGET(FOR_ITER_TUPLE) { - PyObject *iter = stack_pointer[-1]; - PyObject *next; - _PyTupleIterObject *it = (_PyTupleIterObject *)iter; - DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); - STAT_INC(FOR_ITER, hit); - PyTupleObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyTuple_GET_SIZE(seq)) { - next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); - goto end_for_iter_tuple; // End of this instruction + PyObject *_tmp_1; + PyObject *_tmp_2 = stack_pointer[-1]; + { + PyObject *iter = _tmp_2; + DEOPT_IF(Py_TYPE(iter) != &PyTupleIter_Type, FOR_ITER); + _tmp_2 = iter; + } + { + PyObject *iter = _tmp_2; + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + STAT_INC(FOR_ITER, hit); + PyTupleObject *seq = it->it_seq; + if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + if (seq != NULL) { + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); + /* Jump forward oparg, then skip following END_FOR instruction */ + JUMPBY(oparg + 1); + DISPATCH(); } - it->it_seq = NULL; - Py_DECREF(seq); + _tmp_2 = iter; + } + { + PyObject *iter = _tmp_2; + PyObject *next; + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + assert(Py_TYPE(iter) == &PyTupleIter_Type); + PyTupleObject *seq = it->it_seq; + assert(seq); + assert(it->it_index < PyTuple_GET_SIZE(seq)); + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); + _tmp_2 = iter; + _tmp_1 = next; } - Py_DECREF(iter); - STACK_SHRINK(1); - SKIP_OVER(INLINE_CACHE_ENTRIES_FOR_ITER); - /* Jump forward oparg, then skip following END_FOR instruction */ - JUMPBY(oparg + 1); - DISPATCH(); - end_for_iter_tuple: - // Common case: no jump, leave it to the code generator - STACK_GROW(1); - stack_pointer[-1] = next; next_instr += 1; + STACK_GROW(1); + stack_pointer[-1] = _tmp_1; + stack_pointer[-2] = _tmp_2; DISPATCH(); } diff --git a/Python/optimizer.c b/Python/optimizer.c index abd2351f6b78bd..289b202f806ae1 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -378,6 +378,7 @@ translate_bytecode_to_trace( _Py_CODEUNIT *initial_instr = instr; int trace_length = 0; int max_length = buffer_size; + int reserved = 0; #ifdef Py_DEBUG char *uop_debug = Py_GETENV("PYTHONUOPSDEBUG"); @@ -385,6 +386,9 @@ translate_bytecode_to_trace( if (uop_debug != NULL && *uop_debug >= '0') { lltrace = *uop_debug - '0'; // TODO: Parse an int and all that } +#endif + +#ifdef Py_DEBUG #define DPRINTF(level, ...) \ if (lltrace >= (level)) { fprintf(stderr, __VA_ARGS__); } #else @@ -397,6 +401,8 @@ translate_bytecode_to_trace( uop_name(OPCODE), \ (uint64_t)(OPERAND)); \ assert(trace_length < max_length); \ + assert(reserved > 0); \ + reserved--; \ trace[trace_length].opcode = (OPCODE); \ trace[trace_length].operand = (OPERAND); \ trace_length++; @@ -409,9 +415,23 @@ translate_bytecode_to_trace( (INDEX), \ uop_name(OPCODE), \ (uint64_t)(OPERAND)); \ + assert(reserved > 0); \ + reserved--; \ trace[(INDEX)].opcode = (OPCODE); \ trace[(INDEX)].operand = (OPERAND); +// Reserve space for n uops +#define RESERVE_RAW(n, opname) \ + if (trace_length + (n) > max_length) { \ + DPRINTF(2, "No room for %s (need %d, got %d)\n", \ + (opname), (n), max_length - trace_length); \ + goto done; \ + } \ + reserved = (n); // Keep ADD_TO_TRACE / ADD_TO_STUB honest + +// Reserve space for main+stub uops, plus 2 for SAVE_IP and EXIT_TRACE +#define RESERVE(main, stub) RESERVE_RAW((main) + (stub) + 2, uop_name(opcode)) + DPRINTF(4, "Optimizing %s (%s:%d) at byte offset %ld\n", PyUnicode_AsUTF8(code->co_qualname), @@ -420,16 +440,20 @@ translate_bytecode_to_trace( 2 * INSTR_IP(initial_instr, code)); for (;;) { + RESERVE_RAW(2, "epilogue"); // Always need space for SAVE_IP and EXIT_TRACE ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code)); + int opcode = instr->op.code; int oparg = instr->op.arg; int extras = 0; + while (opcode == EXTENDED_ARG) { instr++; extras += 1; opcode = instr->op.code; oparg = (oparg << 8) | instr->op.arg; } + if (opcode == ENTER_EXECUTOR) { _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; @@ -437,17 +461,14 @@ translate_bytecode_to_trace( DPRINTF(2, " * ENTER_EXECUTOR -> %s\n", _PyOpcode_OpName[opcode]); oparg = (oparg & 0xffffff00) | executor->vm_data.oparg; } + switch (opcode) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { // Assume jump unlikely (TODO: handle jump likely case) - // Reserve 5 entries (1 here, 2 stub, plus SAVE_IP + EXIT_TRACE) - if (trace_length + 5 > max_length) { - DPRINTF(1, "Ran out of space for POP_JUMP_IF_FALSE\n"); - goto done; - } + RESERVE(1, 2); _Py_CODEUNIT *target_instr = instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg; max_length -= 2; // Really the start of the stubs @@ -461,9 +482,8 @@ translate_bytecode_to_trace( case JUMP_BACKWARD: { - if (instr + 2 - oparg == initial_instr - && trace_length + 3 <= max_length) - { + if (instr + 2 - oparg == initial_instr) { + RESERVE(1, 0); ADD_TO_TRACE(JUMP_TO_TOP, 0); } else { @@ -474,26 +494,45 @@ translate_bytecode_to_trace( case JUMP_FORWARD: { + RESERVE(0, 0); // This will emit two SAVE_IP instructions; leave it to the optimizer instr += oparg; break; } + case FOR_ITER_LIST: + case FOR_ITER_TUPLE: case FOR_ITER_RANGE: { - // Assume jump unlikely (can a for-loop exit be likely?) - // Reserve 9 entries (4 here, 3 stub, plus SAVE_IP + EXIT_TRACE) - if (trace_length + 9 > max_length) { - DPRINTF(1, "Ran out of space for FOR_ITER_RANGE\n"); - goto done; + RESERVE(4, 3); + int check_op, exhausted_op, next_op; + switch (opcode) { + case FOR_ITER_LIST: + check_op = _ITER_CHECK_LIST; + exhausted_op = _IS_ITER_EXHAUSTED_LIST; + next_op = _ITER_NEXT_LIST; + break; + case FOR_ITER_TUPLE: + check_op = _ITER_CHECK_TUPLE; + exhausted_op = _IS_ITER_EXHAUSTED_TUPLE; + next_op = _ITER_NEXT_TUPLE; + break; + case FOR_ITER_RANGE: + check_op = _ITER_CHECK_RANGE; + exhausted_op = _IS_ITER_EXHAUSTED_RANGE; + next_op = _ITER_NEXT_RANGE; + break; + default: + Py_UNREACHABLE(); } + // Assume jump unlikely (can a for-loop exit be likely?) _Py_CODEUNIT *target_instr = // +1 at the end skips over END_FOR instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg + 1; max_length -= 3; // Really the start of the stubs - ADD_TO_TRACE(_ITER_CHECK_RANGE, 0); - ADD_TO_TRACE(_ITER_EXHAUSTED_RANGE, 0); + ADD_TO_TRACE(check_op, 0); + ADD_TO_TRACE(exhausted_op, 0); ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length); - ADD_TO_TRACE(_ITER_NEXT_RANGE, 0); + ADD_TO_TRACE(next_op, 0); ADD_TO_STUB(max_length + 0, POP_TOP, 0); ADD_TO_STUB(max_length + 1, SAVE_IP, INSTR_IP(target_instr, code)); @@ -507,10 +546,7 @@ translate_bytecode_to_trace( if (expansion->nuops > 0) { // Reserve space for nuops (+ SAVE_IP + EXIT_TRACE) int nuops = expansion->nuops; - if (trace_length + nuops + 2 > max_length) { - DPRINTF(1, "Ran out of space for %s\n", uop_name(opcode)); - goto done; - } + RESERVE(nuops, 0); for (int i = 0; i < nuops; i++) { uint64_t operand; int offset = expansion->uops[i].offset; @@ -556,12 +592,14 @@ translate_bytecode_to_trace( } DPRINTF(2, "Unsupported opcode %s\n", uop_name(opcode)); goto done; // Break out of loop - } - } + } // End default + + } // End switch (opcode) + instr++; // Add cache size for opcode instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]; - } + } // End for (;;) done: // Skip short traces like SAVE_IP, LOAD_FAST, SAVE_IP, EXIT_TRACE @@ -610,6 +648,9 @@ translate_bytecode_to_trace( } return 0; +#undef RESERVE +#undef RESERVE_RAW +#undef INSTR_IP #undef ADD_TO_TRACE #undef DPRINTF } From 490295d651d04ec3b3eff2a2cda7501191bad78a Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 14 Jul 2023 09:55:49 +0300 Subject: [PATCH 390/446] gh-105626: Change the default return value of `HTTPConnection.get_proxy_response_headers` (#105628) --- Doc/library/http.client.rst | 2 +- Lib/http/client.py | 5 ++--- Lib/test/test_httplib.py | 13 +++++++++++++ .../2023-06-10-12-20-17.gh-issue-105626.XyZein.rst | 3 +++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst diff --git a/Doc/library/http.client.rst b/Doc/library/http.client.rst index 45291933d635b9..b9ceab699cef63 100644 --- a/Doc/library/http.client.rst +++ b/Doc/library/http.client.rst @@ -390,7 +390,7 @@ HTTPConnection Objects Returns a dictionary with the headers of the response received from the proxy server to the CONNECT request. - If the CONNECT request was not sent, the method returns an empty dictionary. + If the CONNECT request was not sent, the method returns ``None``. .. versionadded:: 3.12 diff --git a/Lib/http/client.py b/Lib/http/client.py index 3d98e4eb54bb45..b35b1d6368aae7 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -970,13 +970,12 @@ def get_proxy_response_headers(self): received from the proxy server to the CONNECT request sent to set the tunnel. - If the CONNECT request was not sent, the method returns - an empty dictionary. + If the CONNECT request was not sent, the method returns None. """ return ( _parse_header_lines(self._raw_proxy_headers) if self._raw_proxy_headers is not None - else {} + else None ) def connect(self): diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 8955d45fa93dd4..fe8105ee2bb3fa 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -2404,6 +2404,19 @@ def test_proxy_response_headers(self): headers = self.conn.get_proxy_response_headers() self.assertIn(expected_header, headers.items()) + def test_no_proxy_response_headers(self): + expected_header = ('X-Dummy', '1') + response_text = ( + 'HTTP/1.0 200 OK\r\n' + '{0}\r\n\r\n'.format(':'.join(expected_header)) + ) + + self.conn._create_connection = self._create_connection(response_text) + + self.conn.request('PUT', '/', '') + headers = self.conn.get_proxy_response_headers() + self.assertIsNone(headers) + def test_tunnel_leak(self): sock = None diff --git a/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst b/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst new file mode 100644 index 00000000000000..2a48361fa596c9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-10-12-20-17.gh-issue-105626.XyZein.rst @@ -0,0 +1,3 @@ +Change the default return value of +:meth:`http.client.HTTPConnection.get_proxy_response_headers` to be ``None`` +and not ``{}``. From 21d98be42289369ccfbdcc38574cb9ab50ce1c02 Mon Sep 17 00:00:00 2001 From: Grant Ramsay Date: Fri, 14 Jul 2023 19:10:54 +1200 Subject: [PATCH 391/446] gh-105293: Do not call SSL_CTX_set_session_id_context on client side SSL context (#105295) * gh-105293: Do not call SSL_CTX_set_session_id_context on client side SSL context Openssl states this is a "server side only" operation. Calling this on a client side socket can result in unexpected behavior * Add news entry on SSL "set session id context" changes --- .../2023-07-14-14-53-58.gh-issue-105293.kimf_i.rst | 2 ++ Modules/_ssl.c | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-14-14-53-58.gh-issue-105293.kimf_i.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-14-14-53-58.gh-issue-105293.kimf_i.rst b/Misc/NEWS.d/next/Library/2023-07-14-14-53-58.gh-issue-105293.kimf_i.rst new file mode 100644 index 00000000000000..c263c8524aa962 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-14-14-53-58.gh-issue-105293.kimf_i.rst @@ -0,0 +1,2 @@ +Remove call to ``SSL_CTX_set_session_id_context`` during client side context +creation in the :mod:`ssl` module. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index df1496925f678e..571de331e92cd9 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -847,6 +847,15 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); return NULL; } + + if (socket_type == PY_SSL_SERVER) { +#define SID_CTX "Python" + /* Set the session id context (server-side only) */ + SSL_set_session_id_context(self->ssl, (const unsigned char *) SID_CTX, + sizeof(SID_CTX)); +#undef SID_CTX + } + /* bpo43522 and OpenSSL < 1.1.1l: copy hostflags manually */ #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION < 0x101010cf X509_VERIFY_PARAM *ssl_params = SSL_get0_param(self->ssl); @@ -3186,11 +3195,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) usage for no cost at all. */ SSL_CTX_set_mode(self->ctx, SSL_MODE_RELEASE_BUFFERS); -#define SID_CTX "Python" - SSL_CTX_set_session_id_context(self->ctx, (const unsigned char *) SID_CTX, - sizeof(SID_CTX)); -#undef SID_CTX - params = SSL_CTX_get0_param(self->ctx); /* Improve trust chain building when cross-signed intermediate certificates are present. See https://bugs.python.org/issue23476. */ From 89867d2491c0c3ef77bc237899b2f0762f43c03c Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Fri, 14 Jul 2023 15:38:03 +0800 Subject: [PATCH 392/446] gh-106446: Fix failed doctest in stdtypes (#106447) --------- Co-authored-by: Terry Jan Reedy --- Doc/library/stdtypes.rst | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 8e049d9645c0b6..fd51b1187576b1 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -3953,7 +3953,7 @@ copying. >>> m = memoryview(bytearray(b'abc')) >>> mm = m.toreadonly() >>> mm.tolist() - [89, 98, 99] + [97, 98, 99] >>> mm[0] = 42 Traceback (most recent call last): File "", line 1, in @@ -4009,6 +4009,7 @@ copying. :mod:`struct` syntax. One of the formats must be a byte format ('B', 'b' or 'c'). The byte length of the result must be the same as the original length. + Note that all byte lengths may depend on the operating system. Cast 1D/long to 1D/unsigned bytes:: @@ -4039,8 +4040,8 @@ copying. >>> x = memoryview(b) >>> x[0] = b'a' Traceback (most recent call last): - File "", line 1, in - ValueError: memoryview: invalid value for format "B" + ... + TypeError: memoryview: invalid type for format 'B' >>> y = x.cast('c') >>> y[0] = b'a' >>> b @@ -4789,10 +4790,10 @@ An example of dictionary view usage:: >>> # set operations >>> keys & {'eggs', 'bacon', 'salad'} {'bacon'} - >>> keys ^ {'sausage', 'juice'} - {'juice', 'sausage', 'bacon', 'spam'} - >>> keys | ['juice', 'juice', 'juice'] - {'juice', 'sausage', 'bacon', 'spam', 'eggs'} + >>> keys ^ {'sausage', 'juice'} == {'juice', 'sausage', 'bacon', 'spam'} + True + >>> keys | ['juice', 'juice', 'juice'] == {'bacon', 'spam', 'juice'} + True >>> # get back a read-only proxy for the original dictionary >>> values.mapping @@ -4999,8 +5000,8 @@ exception to disallow mistakes like ``dict[str][str]``:: >>> dict[str][str] Traceback (most recent call last): - File "", line 1, in - TypeError: There are no type variables left in dict[str] + ... + TypeError: dict[str] is not a generic class However, such expressions are valid when :ref:`type variables ` are used. The index must have as many elements as there are type variable items @@ -5206,13 +5207,15 @@ enables cleaner type hinting syntax compared to :data:`typing.Union`. >>> isinstance("", int | str) True - However, union objects containing :ref:`parameterized generics - ` cannot be used:: + However, :ref:`parameterized generics ` in + union objects cannot be checked:: - >>> isinstance(1, int | list[int]) + >>> isinstance(1, int | list[int]) # short-circuit evaluation + True + >>> isinstance([1], int | list[int]) Traceback (most recent call last): - File "", line 1, in - TypeError: isinstance() argument 2 cannot contain a parameterized generic + ... + TypeError: isinstance() argument 2 cannot be a parameterized generic The user-exposed type for the union object can be accessed from :data:`types.UnionType` and used for :func:`isinstance` checks. An object cannot be @@ -5515,7 +5518,7 @@ types, where they are relevant. Some of these are not reported by the definition order. Example:: >>> int.__subclasses__() - [] + [, , , ] .. _int_max_str_digits: @@ -5551,7 +5554,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> _ = int('2' * 5432) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. + ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit >>> i = int('2' * 4300) >>> len(str(i)) 4300 @@ -5559,7 +5562,7 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised: >>> len(str(i_squared)) Traceback (most recent call last): ... - ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. + ValueError: Exceeds the limit (4300 digits) for integer string conversion; use sys.set_int_max_str_digits() to increase the limit >>> len(hex(i_squared)) 7144 >>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited. From 7c95345e4f93f4a2475418f17df5aae39dea861f Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 14 Jul 2023 14:20:58 +0200 Subject: [PATCH 393/446] gh-104050: Argument Clinic: Annotate `output_templates()` (#106732) Co-authored-by: AlexWaygood --- Tools/clinic/clinic.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 2dce33690993dd..726ebc04f55bd5 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -792,11 +792,14 @@ def docstring_for_c_string( add('"') return ''.join(text) - def output_templates(self, f): + def output_templates( + self, + f: Function + ) -> dict[str, str]: parameters = list(f.parameters.values()) assert parameters - assert isinstance(parameters[0].converter, self_converter) - del parameters[0] + first_param = parameters.pop(0) + assert isinstance(first_param.converter, self_converter) requires_defining_class = False if parameters and isinstance(parameters[0].converter, defining_class_converter): requires_defining_class = True @@ -809,7 +812,7 @@ def output_templates(self, f): new_or_init = f.kind.new_or_init - vararg = NO_VARARG + vararg: int | str = NO_VARARG pos_only = min_pos = max_pos = min_kw_only = pseudo_args = 0 for i, p in enumerate(parameters, 1): if p.is_keyword_only(): @@ -897,7 +900,7 @@ def output_templates(self, f): # parser_body_fields remembers the fields passed in to the # previous call to parser_body. this is used for an awful hack. - parser_body_fields = () + parser_body_fields: tuple[str, ...] = () def parser_body( prototype: str, *fields: str, @@ -932,6 +935,7 @@ def parser_body( return linear_format(output(), parser_declarations=declarations) if not parameters: + parser_code: list[str] | None if not requires_defining_class: # no parameters, METH_NOARGS flags = "METH_NOARGS" @@ -1165,7 +1169,7 @@ def parser_body( flags = 'METH_METHOD|' + flags parser_prototype = parser_prototype_def_class - add_label = None + add_label: str | None = None for i, p in enumerate(parameters): if isinstance(p.converter, defining_class_converter): raise ValueError("defining_class should be the first " @@ -1308,6 +1312,8 @@ def parser_body( cpp_if = "#if " + conditional cpp_endif = "#endif /* " + conditional + " */" + assert clinic is not None + assert f.full_name is not None if methoddef_define and f.full_name not in clinic.ifndef_symbols: clinic.ifndef_symbols.add(f.full_name) methoddef_ifndef = normalize_snippet(""" From 243fdcb40ebeb177ce723911c1f7fad8a1fdf6cb Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 14 Jul 2023 13:38:28 -0400 Subject: [PATCH 394/446] gh-106531: Remove importlib.resources._legacy (#106532) * gh-106531: Remove importlib.resources._legacy Syncs with importlib_resources 6.0. * Remove documentation for removed functionality. --- Doc/library/importlib.resources.rst | 156 ------------------ Lib/importlib/resources/__init__.py | 19 --- Lib/importlib/resources/_legacy.py | 120 -------------- ...-07-07-16-19-59.gh-issue-106531.eMfNm8.rst | 3 + 4 files changed, 3 insertions(+), 295 deletions(-) delete mode 100644 Lib/importlib/resources/_legacy.py create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-16-19-59.gh-issue-106531.eMfNm8.rst diff --git a/Doc/library/importlib.resources.rst b/Doc/library/importlib.resources.rst index 755693840fecd8..76faf731144779 100644 --- a/Doc/library/importlib.resources.rst +++ b/Doc/library/importlib.resources.rst @@ -94,159 +94,3 @@ for example, a package and its resources can be imported from a zip file using the file system is required. .. versionadded:: 3.9 - - -Deprecated functions -^^^^^^^^^^^^^^^^^^^^ - -An older, deprecated set of functions is still available, but is -scheduled for removal in a future version of Python. -The main drawback of these functions is that they do not support -directories: they assume all resources are located directly within a *package*. - -.. data:: Package - - Whenever a function accepts a ``Package`` argument, you can pass in - either a :class:`module object ` or a module name - as a string. You can only pass module objects whose - ``__spec__.submodule_search_locations`` is not ``None``. - - The ``Package`` type is defined as ``Union[str, ModuleType]``. - - .. deprecated:: 3.12 - - -.. data:: Resource - - For *resource* arguments of the functions below, you can pass in - the name of a resource as a string or - a :class:`path-like object `. - - The ``Resource`` type is defined as ``Union[str, os.PathLike]``. - - -.. function:: open_binary(package, resource) - - Open for binary reading the *resource* within *package*. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. *resource* is the name of the resource to open - within *package*; it may not contain path separators and it may not have - sub-resources (i.e. it cannot be a directory). This function returns a - ``typing.BinaryIO`` instance, a binary I/O stream open for reading. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - files(package).joinpath(resource).open('rb') - - -.. function:: open_text(package, resource, encoding='utf-8', errors='strict') - - Open for text reading the *resource* within *package*. By default, the - resource is opened for reading as UTF-8. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. *resource* is the name of the resource to open - within *package*; it may not contain path separators and it may not have - sub-resources (i.e. it cannot be a directory). *encoding* and *errors* - have the same meaning as with built-in :func:`open`. - - This function returns a ``typing.TextIO`` instance, a text I/O stream open - for reading. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - files(package).joinpath(resource).open('r', encoding=encoding) - - -.. function:: read_binary(package, resource) - - Read and return the contents of the *resource* within *package* as - ``bytes``. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. *resource* is the name of the resource to open - within *package*; it may not contain path separators and it may not have - sub-resources (i.e. it cannot be a directory). This function returns the - contents of the resource as :class:`bytes`. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - files(package).joinpath(resource).read_bytes() - - -.. function:: read_text(package, resource, encoding='utf-8', errors='strict') - - Read and return the contents of *resource* within *package* as a ``str``. - By default, the contents are read as strict UTF-8. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. *resource* is the name of the resource to open - within *package*; it may not contain path separators and it may not have - sub-resources (i.e. it cannot be a directory). *encoding* and *errors* - have the same meaning as with built-in :func:`open`. This function - returns the contents of the resource as :class:`str`. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - files(package).joinpath(resource).read_text(encoding=encoding) - - -.. function:: path(package, resource) - - Return the path to the *resource* as an actual file system path. This - function returns a context manager for use in a :keyword:`with` statement. - The context manager provides a :class:`pathlib.Path` object. - - Exiting the context manager cleans up any temporary file created when the - resource needs to be extracted from e.g. a zip file. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. *resource* is the name of the resource to open - within *package*; it may not contain path separators and it may not have - sub-resources (i.e. it cannot be a directory). - - .. deprecated:: 3.11 - - Calls to this function can be replaced using :func:`as_file`:: - - as_file(files(package).joinpath(resource)) - - -.. function:: is_resource(package, name) - - Return ``True`` if there is a resource named *name* in the package, - otherwise ``False``. - This function does not consider directories to be resources. - *package* is either a name or a module object which conforms to the - ``Package`` requirements. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - files(package).joinpath(resource).is_file() - - -.. function:: contents(package) - - Return an iterable over the named items within the package. The iterable - returns :class:`str` resources (e.g. files) and non-resources - (e.g. directories). The iterable does not recurse into subdirectories. - - *package* is either a name or a module object which conforms to the - ``Package`` requirements. - - .. deprecated:: 3.11 - - Calls to this function can be replaced by:: - - (resource.name for resource in files(package).iterdir() if resource.is_file()) diff --git a/Lib/importlib/resources/__init__.py b/Lib/importlib/resources/__init__.py index 34e3a9950cc557..e6b60c18caa052 100644 --- a/Lib/importlib/resources/__init__.py +++ b/Lib/importlib/resources/__init__.py @@ -6,31 +6,12 @@ Package, ) -from ._legacy import ( - contents, - open_binary, - read_binary, - open_text, - read_text, - is_resource, - path, - Resource, -) - from .abc import ResourceReader __all__ = [ 'Package', - 'Resource', 'ResourceReader', 'as_file', - 'contents', 'files', - 'is_resource', - 'open_binary', - 'open_text', - 'path', - 'read_binary', - 'read_text', ] diff --git a/Lib/importlib/resources/_legacy.py b/Lib/importlib/resources/_legacy.py deleted file mode 100644 index b1ea8105dad6e2..00000000000000 --- a/Lib/importlib/resources/_legacy.py +++ /dev/null @@ -1,120 +0,0 @@ -import functools -import os -import pathlib -import types -import warnings - -from typing import Union, Iterable, ContextManager, BinaryIO, TextIO, Any - -from . import _common - -Package = Union[types.ModuleType, str] -Resource = str - - -def deprecated(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - warnings.warn( - f"{func.__name__} is deprecated. Use files() instead. " - "Refer to https://importlib-resources.readthedocs.io" - "/en/latest/using.html#migrating-from-legacy for migration advice.", - DeprecationWarning, - stacklevel=2, - ) - return func(*args, **kwargs) - - return wrapper - - -def normalize_path(path: Any) -> str: - """Normalize a path by ensuring it is a string. - - If the resulting string contains path separators, an exception is raised. - """ - str_path = str(path) - parent, file_name = os.path.split(str_path) - if parent: - raise ValueError(f'{path!r} must be only a file name') - return file_name - - -@deprecated -def open_binary(package: Package, resource: Resource) -> BinaryIO: - """Return a file-like object opened for binary reading of the resource.""" - return (_common.files(package) / normalize_path(resource)).open('rb') - - -@deprecated -def read_binary(package: Package, resource: Resource) -> bytes: - """Return the binary contents of the resource.""" - return (_common.files(package) / normalize_path(resource)).read_bytes() - - -@deprecated -def open_text( - package: Package, - resource: Resource, - encoding: str = 'utf-8', - errors: str = 'strict', -) -> TextIO: - """Return a file-like object opened for text reading of the resource.""" - return (_common.files(package) / normalize_path(resource)).open( - 'r', encoding=encoding, errors=errors - ) - - -@deprecated -def read_text( - package: Package, - resource: Resource, - encoding: str = 'utf-8', - errors: str = 'strict', -) -> str: - """Return the decoded string of the resource. - - The decoding-related arguments have the same semantics as those of - bytes.decode(). - """ - with open_text(package, resource, encoding, errors) as fp: - return fp.read() - - -@deprecated -def contents(package: Package) -> Iterable[str]: - """Return an iterable of entries in `package`. - - Note that not all entries are resources. Specifically, directories are - not considered resources. Use `is_resource()` on each entry returned here - to check if it is a resource or not. - """ - return [path.name for path in _common.files(package).iterdir()] - - -@deprecated -def is_resource(package: Package, name: str) -> bool: - """True if `name` is a resource inside `package`. - - Directories are *not* resources. - """ - resource = normalize_path(name) - return any( - traversable.name == resource and traversable.is_file() - for traversable in _common.files(package).iterdir() - ) - - -@deprecated -def path( - package: Package, - resource: Resource, -) -> ContextManager[pathlib.Path]: - """A context manager providing a file path object to the resource. - - If the resource does not already exist on its own on the file system, - a temporary file will be created. If the file was created, the file - will be deleted upon exiting the context manager (no exception is - raised if the file was deleted prior to the context manager - exiting). - """ - return _common.as_file(_common.files(package) / normalize_path(resource)) diff --git a/Misc/NEWS.d/next/Library/2023-07-07-16-19-59.gh-issue-106531.eMfNm8.rst b/Misc/NEWS.d/next/Library/2023-07-07-16-19-59.gh-issue-106531.eMfNm8.rst new file mode 100644 index 00000000000000..a52107103c4576 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-16-19-59.gh-issue-106531.eMfNm8.rst @@ -0,0 +1,3 @@ +Removed ``_legacy`` and the names it provided from ``importlib.resources``: +``Resource``, ``contents``, ``is_resource``, ``open_binary``, ``open_text``, +``path``, ``read_binary``, and ``read_text``. From 6a70edf24ca217c5ed4a556d0df5748fc775c762 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 14 Jul 2023 18:41:52 +0100 Subject: [PATCH 395/446] gh-105481: expose opcode metadata via the _opcode module (#106688) --- Include/cpython/compile.h | 6 + Include/internal/pycore_opcode_metadata.h | 32 +- Lib/test/test__opcode.py | 64 ++++ ...-07-13-16-04-15.gh-issue-105481.pYSwMj.rst | 1 + Modules/_opcode.c | 91 +++++ Modules/clinic/_opcode.c.h | 317 +++++++++++++++++- Python/compile.c | 32 ++ Python/flowgraph.c | 4 +- Tools/cases_generator/generate_cases.py | 32 +- 9 files changed, 558 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index f5a62a8ec6dd0c..cd7fd7bd377663 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -67,3 +67,9 @@ typedef struct { #define PY_INVALID_STACK_EFFECT INT_MAX PyAPI_FUNC(int) PyCompile_OpcodeStackEffect(int opcode, int oparg); PyAPI_FUNC(int) PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump); + +PyAPI_FUNC(int) PyUnstable_OpcodeIsValid(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasArg(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasConst(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasName(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index e94732b64384b5..8373f56653b1c7 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -3,6 +3,8 @@ // Python/bytecodes.c // Do not edit! +#include + #define IS_PSEUDO_INSTR(OP) ( \ ((OP) == LOAD_CLOSURE) || \ @@ -941,14 +943,20 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { #endif enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000, INSTR_FMT_IBC00000000, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC0, INSTR_FMT_IXC00, INSTR_FMT_IXC000 }; + +#define IS_VALID_OPCODE(OP) \ + (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \ + (_PyOpcode_opcode_metadata[(OP)].valid_entry)) + #define HAS_ARG_FLAG (1) #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) #define HAS_JUMP_FLAG (8) -#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_ARG_FLAG)) -#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_CONST_FLAG)) -#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_NAME_FLAG)) -#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[(OP)].flags & (HAS_JUMP_FLAG)) +#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) +#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) +#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) +#define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_JUMP_FLAG)) + struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -971,12 +979,16 @@ struct opcode_macro_expansion { #define SAME_OPCODE_METADATA(OP1, OP2) \ (OPCODE_METADATA_FMT(OP1) == OPCODE_METADATA_FMT(OP2)) +#define OPCODE_METADATA_SIZE 512 +#define OPCODE_UOP_NAME_SIZE 512 +#define OPCODE_MACRO_EXPANSION_SIZE 256 + #ifndef NEED_OPCODE_METADATA -extern const struct opcode_metadata _PyOpcode_opcode_metadata[512]; -extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; -extern const char * const _PyOpcode_uop_name[512]; +extern const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE]; +extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE]; +extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE]; #else // if NEED_OPCODE_METADATA -const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { +const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1194,7 +1206,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[512] = { [CACHE] = { true, INSTR_FMT_IX, 0 }, [RESERVED] = { true, INSTR_FMT_IX, 0 }, }; -const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { +const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] = { [NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } }, [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } }, [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, @@ -1308,7 +1320,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; -const char * const _PyOpcode_uop_name[512] = { +const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [EXIT_TRACE] = "EXIT_TRACE", [SAVE_IP] = "SAVE_IP", [_GUARD_BOTH_INT] = "_GUARD_BOTH_INT", diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 3e084928844d2f..7d9553d9e383a3 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -9,6 +9,70 @@ class OpcodeTests(unittest.TestCase): + def check_bool_function_result(self, func, ops, expected): + for op in ops: + if isinstance(op, str): + op = dis.opmap[op] + with self.subTest(opcode=op, func=func): + self.assertIsInstance(func(op), bool) + self.assertEqual(func(op), expected) + + def test_invalid_opcodes(self): + invalid = [-100, -1, 255, 512, 513, 1000] + self.check_bool_function_result(_opcode.is_valid, invalid, False) + self.check_bool_function_result(_opcode.has_arg, invalid, False) + self.check_bool_function_result(_opcode.has_const, invalid, False) + self.check_bool_function_result(_opcode.has_name, invalid, False) + self.check_bool_function_result(_opcode.has_jump, invalid, False) + + def test_is_valid(self): + names = [ + 'CACHE', + 'POP_TOP', + 'IMPORT_NAME', + 'JUMP', + 'INSTRUMENTED_RETURN_VALUE', + ] + opcodes = [dis.opmap[opname] for opname in names] + self.check_bool_function_result(_opcode.is_valid, opcodes, True) + + def test_has_arg(self): + has_arg = ['SWAP', 'LOAD_FAST', 'INSTRUMENTED_POP_JUMP_IF_TRUE', 'JUMP'] + no_arg = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_arg, has_arg, True) + self.check_bool_function_result(_opcode.has_arg, no_arg, False) + + def test_has_const(self): + has_const = ['LOAD_CONST', 'RETURN_CONST', 'KW_NAMES'] + no_const = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_const, has_const, True) + self.check_bool_function_result(_opcode.has_const, no_const, False) + + def test_has_name(self): + has_name = ['STORE_NAME', 'DELETE_ATTR', 'STORE_GLOBAL', 'IMPORT_FROM', + 'LOAD_FROM_DICT_OR_GLOBALS'] + no_name = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_name, has_name, True) + self.check_bool_function_result(_opcode.has_name, no_name, False) + + def test_has_jump(self): + has_jump = ['FOR_ITER', 'JUMP_FORWARD', 'JUMP', 'POP_JUMP_IF_TRUE', 'SEND'] + no_jump = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] + self.check_bool_function_result(_opcode.has_jump, has_jump, True) + self.check_bool_function_result(_opcode.has_jump, no_jump, False) + + # the following test is part of the refactor, it will be removed soon + def test_against_legacy_bool_values(self): + # limiting to ops up to ENTER_EXECUTOR, because everything after that + # is not currently categorized correctly in opcode.py. + for op in range(0, opcode.opmap['ENTER_EXECUTOR']): + with self.subTest(op=op): + if opcode.opname[op] != f'<{op}>': + self.assertEqual(op in dis.hasarg, _opcode.has_arg(op)) + self.assertEqual(op in dis.hasconst, _opcode.has_const(op)) + self.assertEqual(op in dis.hasname, _opcode.has_name(op)) + self.assertEqual(op in dis.hasjrel, _opcode.has_jump(op)) + def test_stack_effect(self): self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) diff --git a/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst new file mode 100644 index 00000000000000..bc2ba51d31aa9c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-13-16-04-15.gh-issue-105481.pYSwMj.rst @@ -0,0 +1 @@ +Expose opcode metadata through :mod:`_opcode`. diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 3c0fce48770ac4..b3b9873d21a5be 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -1,4 +1,5 @@ #include "Python.h" +#include "compile.h" #include "opcode.h" #include "internal/pycore_code.h" @@ -61,6 +62,91 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg, /*[clinic input] +_opcode.is_valid -> bool + + opcode: int + +Return True if opcode is valid, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_is_valid_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=b0d918ea1d073f65 input=fe23e0aa194ddae0]*/ +{ + return PyUnstable_OpcodeIsValid(opcode); +} + +/*[clinic input] + +_opcode.has_arg -> bool + + opcode: int + +Return True if the opcode uses its oparg, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_arg_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=7a062d3b2dcc0815 input=93d878ba6361db5f]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasArg(opcode); +} + +/*[clinic input] + +_opcode.has_const -> bool + + opcode: int + +Return True if the opcode accesses a constant, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_const_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=c646d5027c634120 input=a6999e4cf13f9410]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasConst(opcode); +} + +/*[clinic input] + +_opcode.has_name -> bool + + opcode: int + +Return True if the opcode accesses an attribute by name, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_name_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=b49a83555c2fa517 input=448aa5e4bcc947ba]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasName(opcode); +} + +/*[clinic input] + +_opcode.has_jump -> bool + + opcode: int + +Return True if the opcode has a jump target, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_jump_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=e9c583c669f1c46a input=35f711274357a0c3]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasJump(opcode); + +} + +/*[clinic input] + _opcode.get_specialization_stats Return the specialization stats @@ -80,6 +166,11 @@ _opcode_get_specialization_stats_impl(PyObject *module) static PyMethodDef opcode_functions[] = { _OPCODE_STACK_EFFECT_METHODDEF + _OPCODE_IS_VALID_METHODDEF + _OPCODE_HAS_ARG_METHODDEF + _OPCODE_HAS_CONST_METHODDEF + _OPCODE_HAS_NAME_METHODDEF + _OPCODE_HAS_JUMP_METHODDEF _OPCODE_GET_SPECIALIZATION_STATS_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/clinic/_opcode.c.h b/Modules/clinic/_opcode.c.h index 3bd3ba02387435..3eb050e470c343 100644 --- a/Modules/clinic/_opcode.c.h +++ b/Modules/clinic/_opcode.c.h @@ -86,6 +86,321 @@ _opcode_stack_effect(PyObject *module, PyObject *const *args, Py_ssize_t nargs, return return_value; } +PyDoc_STRVAR(_opcode_is_valid__doc__, +"is_valid($module, /, opcode)\n" +"--\n" +"\n" +"Return True if opcode is valid, False otherwise."); + +#define _OPCODE_IS_VALID_METHODDEF \ + {"is_valid", _PyCFunction_CAST(_opcode_is_valid), METH_FASTCALL|METH_KEYWORDS, _opcode_is_valid__doc__}, + +static int +_opcode_is_valid_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_is_valid(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "is_valid", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_is_valid_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_arg__doc__, +"has_arg($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode uses its oparg, False otherwise."); + +#define _OPCODE_HAS_ARG_METHODDEF \ + {"has_arg", _PyCFunction_CAST(_opcode_has_arg), METH_FASTCALL|METH_KEYWORDS, _opcode_has_arg__doc__}, + +static int +_opcode_has_arg_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_arg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_arg", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_arg_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_const__doc__, +"has_const($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses a constant, False otherwise."); + +#define _OPCODE_HAS_CONST_METHODDEF \ + {"has_const", _PyCFunction_CAST(_opcode_has_const), METH_FASTCALL|METH_KEYWORDS, _opcode_has_const__doc__}, + +static int +_opcode_has_const_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_const(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_const", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_const_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_name__doc__, +"has_name($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses an attribute by name, False otherwise."); + +#define _OPCODE_HAS_NAME_METHODDEF \ + {"has_name", _PyCFunction_CAST(_opcode_has_name), METH_FASTCALL|METH_KEYWORDS, _opcode_has_name__doc__}, + +static int +_opcode_has_name_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_name(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_name", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_name_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_jump__doc__, +"has_jump($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode has a jump target, False otherwise."); + +#define _OPCODE_HAS_JUMP_METHODDEF \ + {"has_jump", _PyCFunction_CAST(_opcode_has_jump), METH_FASTCALL|METH_KEYWORDS, _opcode_has_jump__doc__}, + +static int +_opcode_has_jump_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_jump(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_jump", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_jump_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_opcode_get_specialization_stats__doc__, "get_specialization_stats($module, /)\n" "--\n" @@ -103,4 +418,4 @@ _opcode_get_specialization_stats(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _opcode_get_specialization_stats_impl(module); } -/*[clinic end generated code: output=21e3d53a659c651a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ae2b2ef56d582180 input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index d9e38cfdefaf23..9e86e06777ffa4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -36,7 +36,9 @@ #include "pycore_pystate.h" // _Py_GetConfig() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() +#define NEED_OPCODE_METADATA #include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#undef NEED_OPCODE_METADATA #define COMP_GENEXP 0 #define COMP_LISTCOMP 1 @@ -864,6 +866,36 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } +int +PyUnstable_OpcodeIsValid(int opcode) +{ + return IS_VALID_OPCODE(opcode); +} + +int +PyUnstable_OpcodeHasArg(int opcode) +{ + return OPCODE_HAS_ARG(opcode); +} + +int +PyUnstable_OpcodeHasConst(int opcode) +{ + return OPCODE_HAS_CONST(opcode); +} + +int +PyUnstable_OpcodeHasName(int opcode) +{ + return OPCODE_HAS_NAME(opcode); +} + +int +PyUnstable_OpcodeHasJump(int opcode) +{ + return OPCODE_HAS_JUMP(opcode); +} + static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 04f269c5853835..e485ed103147a1 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -7,9 +7,7 @@ #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_opcode_utils.h" -#define NEED_OPCODE_METADATA -#include "pycore_opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed -#undef NEED_OPCODE_METADATA +#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc #undef SUCCESS diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ce16271097b955..6589289121863b 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -308,7 +308,7 @@ def emit_macros(cls, out: Formatter): for name, value in flags.bitmask.items(): out.emit( f"#define OPCODE_{name[:-len('_FLAG')]}(OP) " - f"(_PyOpcode_opcode_metadata[(OP)].flags & ({name}))") + f"(_PyOpcode_opcode_metadata[OP].flags & ({name}))") @dataclasses.dataclass @@ -1192,6 +1192,8 @@ def write_metadata(self) -> None: self.write_provenance_header() + self.out.emit("\n#include ") + self.write_pseudo_instrs() self.out.emit("") @@ -1202,8 +1204,16 @@ def write_metadata(self) -> None: # Write type definitions self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") + self.out.emit("") + self.out.emit( + "#define IS_VALID_OPCODE(OP) \\\n" + " (((OP) >= 0) && ((OP) < OPCODE_METADATA_SIZE) && \\\n" + " (_PyOpcode_opcode_metadata[(OP)].valid_entry))") + + self.out.emit("") InstructionFlags.emit_macros(self.out) + self.out.emit("") with self.out.block("struct opcode_metadata", ";"): self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") @@ -1226,13 +1236,20 @@ def write_metadata(self) -> None: self.out.emit("") # Write metadata array declaration + self.out.emit("#define OPCODE_METADATA_SIZE 512") + self.out.emit("#define OPCODE_UOP_NAME_SIZE 512") + self.out.emit("#define OPCODE_MACRO_EXPANSION_SIZE 256") + self.out.emit("") self.out.emit("#ifndef NEED_OPCODE_METADATA") - self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[512];") - self.out.emit("extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];") - self.out.emit("extern const char * const _PyOpcode_uop_name[512];") + self.out.emit("extern const struct opcode_metadata " + "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE];") + self.out.emit("extern const struct opcode_macro_expansion " + "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE];") + self.out.emit("extern const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE];") self.out.emit("#else // if NEED_OPCODE_METADATA") - self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[512] = {") + self.out.emit("const struct opcode_metadata " + "_PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {") # Write metadata for each instruction for thing in self.everything: @@ -1253,7 +1270,8 @@ def write_metadata(self) -> None: self.out.emit("};") with self.out.block( - "const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] =", + "const struct opcode_macro_expansion " + "_PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] =", ";", ): # Write macro expansion for each non-pseudo instruction @@ -1279,7 +1297,7 @@ def write_metadata(self) -> None: case _: typing.assert_never(thing) - with self.out.block("const char * const _PyOpcode_uop_name[512] =", ";"): + with self.out.block("const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] =", ";"): self.write_uop_items(lambda name, counter: f"[{name}] = \"{name}\",") self.out.emit("#endif // NEED_OPCODE_METADATA") From aeef8591e41b68341af308e56a744396c66879cc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 14 Jul 2023 08:46:30 -1000 Subject: [PATCH 396/446] gh-106554: replace `_BaseSelectorImpl._key_from_fd` with `dict.get` (#106555) --- Lib/selectors.py | 21 ++++--------------- ...-07-09-01-59-24.gh-issue-106554.37c53J.rst | 1 + 2 files changed, 5 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-09-01-59-24.gh-issue-106554.37c53J.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index dfcc125dcd94ef..6d82935445d4b1 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -276,19 +276,6 @@ def close(self): def get_map(self): return self._map - def _key_from_fd(self, fd): - """Return the key associated to a given file descriptor. - - Parameters: - fd -- file descriptor - - Returns: - corresponding key, or None if not found - """ - try: - return self._fd_to_key[fd] - except KeyError: - return None class SelectSelector(_BaseSelectorImpl): @@ -336,7 +323,7 @@ def select(self, timeout=None): if fd in w: events |= EVENT_WRITE - key = self._key_from_fd(fd) + key = self._fd_to_key.get(fd) if key: ready.append((key, events & key.events)) return ready @@ -426,7 +413,7 @@ def select(self, timeout=None): if event & ~self._EVENT_WRITE: events |= EVENT_READ - key = self._key_from_fd(fd) + key = self._fd_to_key.get(fd) if key: ready.append((key, events & key.events)) return ready @@ -479,7 +466,7 @@ def select(self, timeout=None): if event & ~select.EPOLLOUT: events |= EVENT_READ - key = self._key_from_fd(fd) + key = self._fd_to_key.get(fd) if key: ready.append((key, events & key.events)) return ready @@ -574,7 +561,7 @@ def select(self, timeout=None): if flag == select.KQ_FILTER_WRITE: events |= EVENT_WRITE - key = self._key_from_fd(fd) + key = self._fd_to_key.get(fd) if key: ready.append((key, events & key.events)) return ready diff --git a/Misc/NEWS.d/next/Library/2023-07-09-01-59-24.gh-issue-106554.37c53J.rst b/Misc/NEWS.d/next/Library/2023-07-09-01-59-24.gh-issue-106554.37c53J.rst new file mode 100644 index 00000000000000..2136f3aa5a8eb0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-09-01-59-24.gh-issue-106554.37c53J.rst @@ -0,0 +1 @@ +:mod:`selectors`: Reduce Selector overhead by using a ``dict.get()`` to lookup file descriptors. From 89ec0e952965b6a1be40e26c3ddc4131599e5ee9 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Fri, 14 Jul 2023 19:49:02 +0100 Subject: [PATCH 397/446] gh-106745: typing docs: Clarify that removal of PEP-585 aliases is not currently planned (#106748) --- Doc/library/typing.rst | 70 +++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 0cf875582f7f42..0265a39ce646f4 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -3101,6 +3101,7 @@ Constant .. versionadded:: 3.5.2 .. _generic-concrete-collections: +.. _deprecated-aliases: Deprecated aliases ------------------ @@ -3109,16 +3110,21 @@ This module defines several deprecated aliases to pre-existing standard library classes. These were originally included in the typing module in order to support parameterizing these generic classes using ``[]``. However, the aliases became redundant in Python 3.9 when the -corresponding pre-existing classes were enhanced to support ``[]``. +corresponding pre-existing classes were enhanced to support ``[]`` (see +:pep:`585`). -The redundant types are deprecated as of Python 3.9 but no -deprecation warnings are issued by the interpreter. -It is expected that type checkers will flag the deprecated types -when the checked program targets Python 3.9 or newer. +The redundant types are deprecated as of Python 3.9. However, while the aliases +may be removed at some point, removal of these aliases is not currently +planned. As such, no deprecation warnings are currently issued by the +interpreter for these aliases. -The deprecated types will be removed from the :mod:`typing` module -no sooner than the first Python version released 5 years after the release of Python 3.9.0. -See details in :pep:`585`—*Type Hinting Generics In Standard Collections*. +If at some point it is decided to remove these deprecated aliases, a +deprecation warning will be issued by the interpreter for at least two releases +prior to removal. The aliases are guaranteed to remain in the typing module +without deprecation warnings until at least Python 3.14. + +Type checkers are encouraged to flag uses of the deprecated types if the +program they are checking targets a minimum Python version of 3.9 or newer. .. _corresponding-to-built-in-types: @@ -3651,20 +3657,34 @@ Certain features in ``typing`` are deprecated and may be removed in a future version of Python. The following table summarizes major deprecations for your convenience. This is subject to change, and not all deprecations are listed. -+-------------------------------------+---------------+-------------------+----------------+ -| Feature | Deprecated in | Projected removal | PEP/issue | -+=====================================+===============+===================+================+ -| ``typing`` versions of standard | 3.9 | Undecided | :pep:`585` | -| collections | | | | -+-------------------------------------+---------------+-------------------+----------------+ -| ``typing.ByteString`` | 3.9 | 3.14 | :gh:`91896` | -+-------------------------------------+---------------+-------------------+----------------+ -| ``typing.Text`` | 3.11 | Undecided | :gh:`92332` | -+-------------------------------------+---------------+-------------------+----------------+ -| ``typing.Hashable`` and | 3.12 | Undecided | :gh:`94309` | -| ``typing.Sized`` | | | | -+-------------------------------------+---------------+-------------------+----------------+ -| ``typing.TypeAlias`` | 3.12 | Undecided | :pep:`695` | -+-------------------------------------+---------------+-------------------+----------------+ -| ``typing.no_type_check_decorator`` | 3.13 | 3.15 | :gh:`106309` | -+-------------------------------------+---------------+-------------------+----------------+ +.. list-table:: + :header-rows: 1 + + * - Feature + - Deprecated in + - Projected removal + - PEP/issue + * - ``typing`` versions of standard collections + - 3.9 + - Undecided (see :ref:`deprecated-aliases` for more information) + - :pep:`585` + * - :class:`typing.ByteString` + - 3.9 + - 3.14 + - :gh:`91896` + * - :data:`typing.Text` + - 3.11 + - Undecided + - :gh:`92332` + * - :class:`typing.Hashable` and :class:`typing.Sized` + - 3.12 + - Undecided + - :gh:`94309` + * - :data:`typing.TypeAlias` + - 3.12 + - Undecided + - :pep:`695` + * - :func:`@typing.no_type_check_decorator ` + - 3.13 + - 3.15 + - :gh:`106309` From fb32f35c0585b1dbb87b6f254818e1f485a50f65 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 14 Jul 2023 20:41:24 +0100 Subject: [PATCH 398/446] gh-102799: replace internal sys.exc_info() call by sys.exception() (#106746) --- Lib/logging/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 2a011b6d2ff15d..46e86cb87ecfcb 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -662,7 +662,7 @@ def formatException(self, ei): # See issues #9427, #1553375. Commented out for now. #if getattr(self, 'fullstack', False): # traceback.print_stack(tb.tb_frame.f_back, file=sio) - traceback.print_exception(ei[0], ei[1], tb, None, sio) + traceback.print_exception(ei[0], ei[1], tb, limit=None, file=sio) s = sio.getvalue() sio.close() if s[-1:] == "\n": @@ -1080,14 +1080,14 @@ def handleError(self, record): The record which was being processed is passed in to this method. """ if raiseExceptions and sys.stderr: # see issue 13807 - t, v, tb = sys.exc_info() + exc = sys.exception() try: sys.stderr.write('--- Logging error ---\n') - traceback.print_exception(t, v, tb, None, sys.stderr) + traceback.print_exception(exc, limit=None, file=sys.stderr) sys.stderr.write('Call stack:\n') # Walk the stack frame up until we're out of logging, # so as to print the calling context. - frame = tb.tb_frame + frame = exc.__traceback__.tb_frame while (frame and os.path.dirname(frame.f_code.co_filename) == __path__[0]): frame = frame.f_back @@ -1112,7 +1112,7 @@ def handleError(self, record): except OSError: #pragma: no cover pass # see issue 5971 finally: - del t, v, tb + del exc def __repr__(self): level = getLevelName(self.level) From 03185f0c150ebc52d41dd5ea6f369c7b5ba9fc16 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 14 Jul 2023 16:40:46 -0400 Subject: [PATCH 399/446] gh-106752: Move zipfile._path into its own package (#106753) * gh-106752: Move zipfile._path into its own package so it may have supplementary behavior. * Add blurb --- .github/CODEOWNERS | 2 +- Lib/test/test_zipfile/_path/__init__.py | 0 Lib/test/test_zipfile/{ => _path}/_functools.py | 0 Lib/test/test_zipfile/{ => _path}/_itertools.py | 0 Lib/test/test_zipfile/{ => _path}/_support.py | 0 Lib/test/test_zipfile/{ => _path}/_test_params.py | 0 Lib/test/test_zipfile/{ => _path}/test_complexity.py | 0 Lib/test/test_zipfile/{ => _path}/test_path.py | 0 Lib/zipfile/{_path.py => _path/__init__.py} | 0 Makefile.pre.in | 3 ++- .../next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst | 2 ++ 11 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_zipfile/_path/__init__.py rename Lib/test/test_zipfile/{ => _path}/_functools.py (100%) rename Lib/test/test_zipfile/{ => _path}/_itertools.py (100%) rename Lib/test/test_zipfile/{ => _path}/_support.py (100%) rename Lib/test/test_zipfile/{ => _path}/_test_params.py (100%) rename Lib/test/test_zipfile/{ => _path}/test_complexity.py (100%) rename Lib/test/test_zipfile/{ => _path}/test_path.py (100%) rename Lib/zipfile/{_path.py => _path/__init__.py} (100%) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5b471c79f75eea..234a954cc7662f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -172,7 +172,7 @@ Doc/c-api/stable.rst @encukou **/*pathlib* @barneygale # zipfile.Path -**/*zipfile/*_path.py @jaraco +**/*zipfile/_path/* @jaraco # Argument Clinic /Tools/clinic/** @erlend-aasland @AlexWaygood diff --git a/Lib/test/test_zipfile/_path/__init__.py b/Lib/test/test_zipfile/_path/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Lib/test/test_zipfile/_functools.py b/Lib/test/test_zipfile/_path/_functools.py similarity index 100% rename from Lib/test/test_zipfile/_functools.py rename to Lib/test/test_zipfile/_path/_functools.py diff --git a/Lib/test/test_zipfile/_itertools.py b/Lib/test/test_zipfile/_path/_itertools.py similarity index 100% rename from Lib/test/test_zipfile/_itertools.py rename to Lib/test/test_zipfile/_path/_itertools.py diff --git a/Lib/test/test_zipfile/_support.py b/Lib/test/test_zipfile/_path/_support.py similarity index 100% rename from Lib/test/test_zipfile/_support.py rename to Lib/test/test_zipfile/_path/_support.py diff --git a/Lib/test/test_zipfile/_test_params.py b/Lib/test/test_zipfile/_path/_test_params.py similarity index 100% rename from Lib/test/test_zipfile/_test_params.py rename to Lib/test/test_zipfile/_path/_test_params.py diff --git a/Lib/test/test_zipfile/test_complexity.py b/Lib/test/test_zipfile/_path/test_complexity.py similarity index 100% rename from Lib/test/test_zipfile/test_complexity.py rename to Lib/test/test_zipfile/_path/test_complexity.py diff --git a/Lib/test/test_zipfile/test_path.py b/Lib/test/test_zipfile/_path/test_path.py similarity index 100% rename from Lib/test/test_zipfile/test_path.py rename to Lib/test/test_zipfile/_path/test_path.py diff --git a/Lib/zipfile/_path.py b/Lib/zipfile/_path/__init__.py similarity index 100% rename from Lib/zipfile/_path.py rename to Lib/zipfile/_path/__init__.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 4b655513f656d7..ddf524ac17d72a 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2125,7 +2125,7 @@ LIBSUBDIRS= asyncio \ wsgiref \ $(XMLLIBSUBDIRS) \ xmlrpc \ - zipfile \ + zipfile zipfile/_path \ zoneinfo \ __phello__ TESTSUBDIRS= idlelib/idle_test \ @@ -2229,6 +2229,7 @@ TESTSUBDIRS= idlelib/idle_test \ test/test_warnings \ test/test_warnings/data \ test/test_zipfile \ + test/test_zipfile/_path \ test/test_zoneinfo \ test/test_zoneinfo/data \ test/tkinterdata \ diff --git a/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst b/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst new file mode 100644 index 00000000000000..ba7257e3610808 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-14-16-20-06.gh-issue-106752.gd1i6D.rst @@ -0,0 +1,2 @@ +Moved tests for ``zipfile.Path`` into ``Lib/test/test_zipfile/_path``. Made +``zipfile._path`` a package. From 0db85eeba762e72f9f3c027e432cdebc627aac6c Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 14 Jul 2023 17:22:06 -0700 Subject: [PATCH 400/446] gh-106529: Fix subtle Tier 2 edge case with list iterator (#106756) The Tier 2 opcode _IS_ITER_EXHAUSTED_LIST (and _TUPLE) didn't set it->it_seq to NULL, causing a subtle bug that resulted in test_exhausted_iterator in list_tests.py to fail when running all tests with -Xuops. The bug was introduced in gh-106696. Added this as an explicit test. Also fixed the dependencies for ceval.o -- it depends on executor_cases.c.h. --- Lib/test/test_capi/test_misc.py | 13 +++++++++++++ Makefile.pre.in | 1 + Python/bytecodes.c | 14 ++++++++++++-- Python/executor_cases.c.h | 14 ++++++++++++-- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 43c04463236a2a..6df918997b2b19 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2649,6 +2649,19 @@ def testfunc(a): # Verification that the jump goes past END_FOR # is done by manual inspection of the output + def test_list_edge_case(self): + def testfunc(it): + for x in it: + pass + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + a = [1, 2, 3] + it = iter(a) + testfunc(it) + a.append(4) + with self.assertRaises(StopIteration): + next(it) if __name__ == "__main__": unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index ddf524ac17d72a..553b2aa480c184 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1564,6 +1564,7 @@ Python/ceval.o: \ $(srcdir)/Python/ceval_macros.h \ $(srcdir)/Python/condvar.h \ $(srcdir)/Python/generated_cases.c.h \ + $(srcdir)/Python/executor_cases.c.h \ $(srcdir)/Include/internal/pycore_opcode_metadata.h \ $(srcdir)/Python/opcode_targets.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 15b48ae9d82672..3432b027713462 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2448,7 +2448,12 @@ dummy_func( _PyListIterObject *it = (_PyListIterObject *)iter; assert(Py_TYPE(iter) == &PyListIter_Type); PyListObject *seq = it->it_seq; - if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + if (seq == NULL) { + exhausted = Py_True; + } + else if (it->it_index >= PyList_GET_SIZE(seq)) { + Py_DECREF(seq); + it->it_seq = NULL; exhausted = Py_True; } else { @@ -2499,7 +2504,12 @@ dummy_func( _PyTupleIterObject *it = (_PyTupleIterObject *)iter; assert(Py_TYPE(iter) == &PyTupleIter_Type); PyTupleObject *seq = it->it_seq; - if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + if (seq == NULL) { + exhausted = Py_True; + } + else if (it->it_index >= PyTuple_GET_SIZE(seq)) { + Py_DECREF(seq); + it->it_seq = NULL; exhausted = Py_True; } else { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 626baece814607..ae21ffad94d801 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1750,7 +1750,12 @@ _PyListIterObject *it = (_PyListIterObject *)iter; assert(Py_TYPE(iter) == &PyListIter_Type); PyListObject *seq = it->it_seq; - if (seq == NULL || it->it_index >= PyList_GET_SIZE(seq)) { + if (seq == NULL) { + exhausted = Py_True; + } + else if (it->it_index >= PyList_GET_SIZE(seq)) { + Py_DECREF(seq); + it->it_seq = NULL; exhausted = Py_True; } else { @@ -1787,7 +1792,12 @@ _PyTupleIterObject *it = (_PyTupleIterObject *)iter; assert(Py_TYPE(iter) == &PyTupleIter_Type); PyTupleObject *seq = it->it_seq; - if (seq == NULL || it->it_index >= PyTuple_GET_SIZE(seq)) { + if (seq == NULL) { + exhausted = Py_True; + } + else if (it->it_index >= PyTuple_GET_SIZE(seq)) { + Py_DECREF(seq); + it->it_seq = NULL; exhausted = Py_True; } else { From 2d7d1aa4bcd5da0177458b22b1b856db76aa20d4 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 15 Jul 2023 11:28:57 +0200 Subject: [PATCH 401/446] gh-106368: Increase Argument Clinic BlockParser test coverage (#106759) --- Lib/test/test_clinic.py | 100 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 975840333e5901..b5744f7013d6ad 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -18,6 +18,19 @@ from clinic import DSLParser +class _ParserBase(TestCase): + maxDiff = None + + def expect_parser_failure(self, parser, _input): + with support.captured_stdout() as stdout: + with self.assertRaises(SystemExit): + parser(_input) + return stdout.getvalue() + + def parse_function_should_fail(self, _input): + return self.expect_parser_failure(self.parse_function, _input) + + class FakeConverter: def __init__(self, name, args): self.name = name @@ -88,7 +101,15 @@ def directive(self, name, args): _module_and_class = clinic.Clinic._module_and_class -class ClinicWholeFileTest(TestCase): + +class ClinicWholeFileTest(_ParserBase): + def setUp(self): + self.clinic = clinic.Clinic(clinic.CLanguage(None), filename="test.c") + + def expect_failure(self, raw): + _input = dedent(raw).strip() + return self.expect_parser_failure(self.clinic.parse, _input) + def test_eol(self): # regression test: # clinic's block parser didn't recognize @@ -98,15 +119,86 @@ def test_eol(self): # so it would spit out an end line for you. # and since you really already had one, # the last line of the block got corrupted. - c = clinic.Clinic(clinic.CLanguage(None), filename="file") raw = "/*[clinic]\nfoo\n[clinic]*/" - cooked = c.parse(raw).splitlines() + cooked = self.clinic.parse(raw).splitlines() end_line = cooked[2].rstrip() # this test is redundant, it's just here explicitly to catch # the regression test so we don't forget what it looked like self.assertNotEqual(end_line, "[clinic]*/[clinic]*/") self.assertEqual(end_line, "[clinic]*/") + def test_mangled_marker_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + /*[clinic end generated code: foo]*/ + """ + msg = ( + 'Error in file "test.c" on line 3:\n' + "Mangled Argument Clinic marker line: '/*[clinic end generated code: foo]*/'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_checksum_mismatch(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + /*[clinic end generated code: output=0123456789abcdef input=fedcba9876543210]*/ + """ + msg = ( + 'Error in file "test.c" on line 3:\n' + 'Checksum mismatch!\n' + 'Expected: 0123456789abcdef\n' + 'Computed: da39a3ee5e6b4b0d\n' + ) + out = self.expect_failure(raw) + self.assertIn(msg, out) + + def test_garbage_after_stop_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/foobarfoobar! + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + "Garbage after stop line: 'foobarfoobar!'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_whitespace_before_stop_line(self): + raw = """ + /*[clinic input] + [clinic start generated code]*/ + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + "Whitespace is not allowed before the stop line: ' [clinic start generated code]*/'\n" + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_parse_with_body_prefix(self): + clang = clinic.CLanguage(None) + clang.body_prefix = "//" + clang.start_line = "//[{dsl_name} start]" + clang.stop_line = "//[{dsl_name} stop]" + cl = clinic.Clinic(clang, filename="test.c") + raw = dedent(""" + //[clinic start] + //module test + //[clinic stop] + """).strip() + out = cl.parse(raw) + expected = dedent(""" + //[clinic start] + //module test + // + //[clinic stop] + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=65fab8adff58cf08]*/ + """).lstrip() # Note, lstrip() because of the newline + self.assertEqual(out, expected) class ClinicGroupPermuterTest(TestCase): @@ -285,7 +377,7 @@ def test_clinic_1(self): """) -class ClinicParserTest(TestCase): +class ClinicParserTest(_ParserBase): def checkDocstring(self, fn, expected): self.assertTrue(hasattr(fn, "docstring")) self.assertEqual(fn.docstring.strip(), From bbf62979851283b601b2dac0073ab331ebeb3be9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 15 Jul 2023 12:11:32 +0200 Subject: [PATCH 402/446] gh-104050: Argument Clinic: Annotate BlockParser (#106750) --- Tools/clinic/clinic.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 726ebc04f55bd5..861a6507eae753 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -1712,7 +1712,13 @@ class BlockParser: Iterator, yields Block objects. """ - def __init__(self, input, language, *, verify=True): + def __init__( + self, + input: str, + language: Language, + *, + verify: bool = True + ) -> None: """ "input" should be a str object with embedded \n characters. @@ -1730,15 +1736,15 @@ def __init__(self, input, language, *, verify=True): self.find_start_re = create_regex(before, after, whole_line=False) self.start_re = create_regex(before, after) self.verify = verify - self.last_checksum_re = None - self.last_dsl_name = None - self.dsl_name = None + self.last_checksum_re: re.Pattern[str] | None = None + self.last_dsl_name: str | None = None + self.dsl_name: str | None = None self.first_block = True - def __iter__(self): + def __iter__(self) -> BlockParser: return self - def __next__(self): + def __next__(self) -> Block: while True: if not self.input: raise StopIteration @@ -1755,18 +1761,18 @@ def __next__(self): return block - def is_start_line(self, line): + def is_start_line(self, line: str) -> str | None: match = self.start_re.match(line.lstrip()) return match.group(1) if match else None - def _line(self, lookahead=False): + def _line(self, lookahead: bool = False) -> str: self.line_number += 1 line = self.input.pop() if not lookahead: self.language.parse_line(line) return line - def parse_verbatim_block(self): + def parse_verbatim_block(self) -> Block: add, output = text_accumulator() self.block_start_line_number = self.line_number @@ -1780,13 +1786,13 @@ def parse_verbatim_block(self): return Block(output()) - def parse_clinic_block(self, dsl_name): + def parse_clinic_block(self, dsl_name: str) -> Block: input_add, input_output = text_accumulator() self.block_start_line_number = self.line_number + 1 stop_line = self.language.stop_line.format(dsl_name=dsl_name) body_prefix = self.language.body_prefix.format(dsl_name=dsl_name) - def is_stop_line(line): + def is_stop_line(line: str) -> bool: # make sure to recognize stop line even if it # doesn't end with EOL (it could be the very end of the file) if line.startswith(stop_line): @@ -1820,6 +1826,7 @@ def is_stop_line(line): checksum_re = create_regex(before, after, word=False) self.last_dsl_name = dsl_name self.last_checksum_re = checksum_re + assert checksum_re is not None # scan forward for checksum line output_add, output_output = text_accumulator() @@ -1834,6 +1841,7 @@ def is_stop_line(line): if self.is_start_line(line): break + output: str | None output = output_output() if arguments: d = {} From 2566b74b26bcce24199427acea392aed644f4b17 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sat, 15 Jul 2023 19:33:32 +0900 Subject: [PATCH 403/446] gh-81283: compiler: remove indent from docstring (#106411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Éric --- Doc/whatsnew/3.13.rst | 7 ++ Include/internal/pycore_compile.h | 2 + Lib/inspect.py | 45 +++++---- Lib/test/test_doctest.py | 4 +- Lib/test/test_inspect.py | 35 ++++++- ...3-07-04-20-42-54.gh-issue-81283.hfh_MD.rst | 3 + Modules/_testinternalcapi.c | 20 +++- Modules/clinic/_testinternalcapi.c.h | 61 +++++++++++- Python/compile.c | 99 ++++++++++++++++++- 9 files changed, 246 insertions(+), 30 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-04-20-42-54.gh-issue-81283.hfh_MD.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 06fcaf4608cdcb..161d5fb1c59a30 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -79,6 +79,13 @@ Other Language Changes * Allow the *count* argument of :meth:`str.replace` to be a keyword. (Contributed by Hugo van Kemenade in :gh:`106487`.) +* Compiler now strip indents from docstrings. + This will reduce the size of :term:`bytecode cache ` (e.g. ``.pyc`` file). + For example, cache file size for ``sqlalchemy.orm.session`` in SQLAlchemy 2.0 + is reduced by about 5%. + This change will affect tools using docstrings, like :mod:`doctest`. + (Contributed by Inada Naoki in :gh:`81283`.) + New Modules =========== diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index e204d4d2457a16..beb37cced06dba 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -91,6 +91,8 @@ int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj); /* Access compiler internals for unit testing */ +PyAPI_FUNC(PyObject*) _PyCompile_CleanDoc(PyObject *doc); + PyAPI_FUNC(PyObject*) _PyCompile_CodeGen( PyObject *ast, PyObject *filename, diff --git a/Lib/inspect.py b/Lib/inspect.py index a550202bb0d49b..15f94a194856ac 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -881,29 +881,28 @@ def cleandoc(doc): Any whitespace that can be uniformly removed from the second line onwards is removed.""" - try: - lines = doc.expandtabs().split('\n') - except UnicodeError: - return None - else: - # Find minimum indentation of any non-blank lines after first line. - margin = sys.maxsize - for line in lines[1:]: - content = len(line.lstrip()) - if content: - indent = len(line) - content - margin = min(margin, indent) - # Remove indentation. - if lines: - lines[0] = lines[0].lstrip() - if margin < sys.maxsize: - for i in range(1, len(lines)): lines[i] = lines[i][margin:] - # Remove any trailing or leading blank lines. - while lines and not lines[-1]: - lines.pop() - while lines and not lines[0]: - lines.pop(0) - return '\n'.join(lines) + lines = doc.expandtabs().split('\n') + + # Find minimum indentation of any non-blank lines after first line. + margin = sys.maxsize + for line in lines[1:]: + content = len(line.lstrip(' ')) + if content: + indent = len(line) - content + margin = min(margin, indent) + # Remove indentation. + if lines: + lines[0] = lines[0].lstrip(' ') + if margin < sys.maxsize: + for i in range(1, len(lines)): + lines[i] = lines[i][margin:] + # Remove any trailing or leading blank lines. + while lines and not lines[-1]: + lines.pop() + while lines and not lines[0]: + lines.pop(0) + return '\n'.join(lines) + def getfile(object): """Work out which source or compiled file an object was defined in.""" diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 542fcdb5cf6f66..bea52c6de7ec6d 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -1287,14 +1287,14 @@ def optionflags(): r""" treated as equal: >>> def f(x): - ... '>>> print(1, 2, 3)\n 1 2\n 3' + ... '\n>>> print(1, 2, 3)\n 1 2\n 3' >>> # Without the flag: >>> test = doctest.DocTestFinder().find(f)[0] >>> doctest.DocTestRunner(verbose=False).run(test) ... # doctest: +ELLIPSIS ********************************************************************** - File ..., line 2, in f + File ..., line 3, in f Failed example: print(1, 2, 3) Expected: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index d89953ab60f022..64afeec351b353 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -596,9 +596,40 @@ def test_finddoc(self): self.assertEqual(finddoc(int.from_bytes), int.from_bytes.__doc__) self.assertEqual(finddoc(int.real), int.real.__doc__) + cleandoc_testdata = [ + # first line should have different margin + (' An\n indented\n docstring.', 'An\nindented\n docstring.'), + # trailing whitespace are not removed. + (' An \n \n indented \n docstring. ', + 'An \n \nindented \n docstring. '), + # NUL is not termination. + ('doc\0string\n\n second\0line\n third\0line\0', + 'doc\0string\n\nsecond\0line\nthird\0line\0'), + # first line is lstrip()-ped. other lines are kept when no margin.[w: + (' ', ''), + # compiler.cleandoc() doesn't strip leading/trailing newlines + # to keep maximum backward compatibility. + # inspect.cleandoc() removes them. + ('\n\n\n first paragraph\n\n second paragraph\n\n', + '\n\n\nfirst paragraph\n\n second paragraph\n\n'), + (' \n \n \n ', '\n \n \n '), + ] + def test_cleandoc(self): - self.assertEqual(inspect.cleandoc('An\n indented\n docstring.'), - 'An\nindented\ndocstring.') + func = inspect.cleandoc + for i, (input, expected) in enumerate(self.cleandoc_testdata): + # only inspect.cleandoc() strip \n + expected = expected.strip('\n') + with self.subTest(i=i): + self.assertEqual(func(input), expected) + + @cpython_only + def test_c_cleandoc(self): + import _testinternalcapi + func = _testinternalcapi.compiler_cleandoc + for i, (input, expected) in enumerate(self.cleandoc_testdata): + with self.subTest(i=i): + self.assertEqual(func(input), expected) def test_getcomments(self): self.assertEqual(inspect.getcomments(mod), '# line 1\n') diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-04-20-42-54.gh-issue-81283.hfh_MD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-20-42-54.gh-issue-81283.hfh_MD.rst new file mode 100644 index 00000000000000..f673c665fe3277 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-04-20-42-54.gh-issue-81283.hfh_MD.rst @@ -0,0 +1,3 @@ +Compiler now strips indents from docstrings. It reduces ``pyc`` file size 5% +when the module is heavily documented. This change affects to ``__doc__`` so +tools like doctest will be affected. diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 7745dd5abc22f0..271ad6cfcaee32 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -15,7 +15,7 @@ #include "pycore_atomic_funcs.h" // _Py_atomic_int_get() #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_bytesobject.h" // _PyBytes_Find() -#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble +#include "pycore_compile.h" // _PyCompile_CodeGen, _PyCompile_OptimizeCfg, _PyCompile_Assemble, _PyCompile_CleanDoc #include "pycore_ceval.h" // _PyEval_AddPendingCall #include "pycore_fileutils.h" // _Py_normpath #include "pycore_frame.h" // _PyInterpreterFrame @@ -704,6 +704,23 @@ set_eval_frame_record(PyObject *self, PyObject *list) Py_RETURN_NONE; } +/*[clinic input] + +_testinternalcapi.compiler_cleandoc -> object + + doc: unicode + +C implementation of inspect.cleandoc(). +[clinic start generated code]*/ + +static PyObject * +_testinternalcapi_compiler_cleandoc_impl(PyObject *module, PyObject *doc) +/*[clinic end generated code: output=2dd203a80feff5bc input=2de03fab931d9cdc]*/ +{ + return _PyCompile_CleanDoc(doc); +} + + /*[clinic input] _testinternalcapi.compiler_codegen -> object @@ -1448,6 +1465,7 @@ static PyMethodDef module_functions[] = { {"DecodeLocaleEx", decode_locale_ex, METH_VARARGS}, {"set_eval_frame_default", set_eval_frame_default, METH_NOARGS, NULL}, {"set_eval_frame_record", set_eval_frame_record, METH_O, NULL}, + _TESTINTERNALCAPI_COMPILER_CLEANDOC_METHODDEF _TESTINTERNALCAPI_COMPILER_CODEGEN_METHODDEF _TESTINTERNALCAPI_OPTIMIZE_CFG_METHODDEF _TESTINTERNALCAPI_ASSEMBLE_CODE_OBJECT_METHODDEF diff --git a/Modules/clinic/_testinternalcapi.c.h b/Modules/clinic/_testinternalcapi.c.h index f5124125874503..9419dcd751a0e9 100644 --- a/Modules/clinic/_testinternalcapi.c.h +++ b/Modules/clinic/_testinternalcapi.c.h @@ -8,6 +8,65 @@ preserve #endif +PyDoc_STRVAR(_testinternalcapi_compiler_cleandoc__doc__, +"compiler_cleandoc($module, /, doc)\n" +"--\n" +"\n" +"C implementation of inspect.cleandoc()."); + +#define _TESTINTERNALCAPI_COMPILER_CLEANDOC_METHODDEF \ + {"compiler_cleandoc", _PyCFunction_CAST(_testinternalcapi_compiler_cleandoc), METH_FASTCALL|METH_KEYWORDS, _testinternalcapi_compiler_cleandoc__doc__}, + +static PyObject * +_testinternalcapi_compiler_cleandoc_impl(PyObject *module, PyObject *doc); + +static PyObject * +_testinternalcapi_compiler_cleandoc(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(doc), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"doc", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "compiler_cleandoc", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + PyObject *doc; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("compiler_cleandoc", "argument 'doc'", "str", args[0]); + goto exit; + } + doc = args[0]; + return_value = _testinternalcapi_compiler_cleandoc_impl(module, doc); + +exit: + return return_value; +} + PyDoc_STRVAR(_testinternalcapi_compiler_codegen__doc__, "compiler_codegen($module, /, ast, filename, optimize, compile_mode=0)\n" "--\n" @@ -206,4 +265,4 @@ _testinternalcapi_assemble_code_object(PyObject *module, PyObject *const *args, exit: return return_value; } -/*[clinic end generated code: output=2965f1578b986218 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=811d50772c8f285a input=a9049054013a1b77]*/ diff --git a/Python/compile.c b/Python/compile.c index 9e86e06777ffa4..b80f7c01bcd90e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1704,10 +1704,16 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts) if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(stmts); if (docstring) { + PyObject *cleandoc = _PyCompile_CleanDoc(docstring); + if (cleandoc == NULL) { + return ERROR; + } i = 1; st = (stmt_ty)asdl_seq_GET(stmts, 0); assert(st->kind == Expr_kind); - VISIT(c, expr, st->v.Expr.value); + location loc = LOC(st->v.Expr.value); + ADDOP_LOAD_CONST(c, loc, cleandoc); + Py_DECREF(cleandoc); RETURN_IF_ERROR(compiler_nameop(c, NO_LOCATION, &_Py_ID(__doc__), Store)); } } @@ -2252,11 +2258,19 @@ compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t f /* if not -OO mode, add docstring */ if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); + if (docstring) { + docstring = _PyCompile_CleanDoc(docstring); + if (docstring == NULL) { + compiler_exit_scope(c); + return ERROR; + } + } } if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { compiler_exit_scope(c); return ERROR; } + Py_XDECREF(docstring); c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args); c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); @@ -7967,6 +7981,89 @@ cfg_to_instructions(cfg_builder *g) return NULL; } +// C implementation of inspect.cleandoc() +// +// Difference from inspect.cleandoc(): +// - Do not remove leading and trailing blank lines to keep lineno. +PyObject * +_PyCompile_CleanDoc(PyObject *doc) +{ + doc = PyObject_CallMethod(doc, "expandtabs", NULL); + if (doc == NULL) { + return NULL; + } + + Py_ssize_t doc_size; + const char *doc_utf8 = PyUnicode_AsUTF8AndSize(doc, &doc_size); + if (doc_utf8 == NULL) { + Py_DECREF(doc); + return NULL; + } + const char *p = doc_utf8; + const char *pend = p + doc_size; + + // First pass: find minimum indentation of any non-blank lines + // after first line. + while (p < pend && *p++ != '\n') { + } + + Py_ssize_t margin = PY_SSIZE_T_MAX; + while (p < pend) { + const char *s = p; + while (*p == ' ') p++; + if (p < pend && *p != '\n') { + margin = Py_MIN(margin, p - s); + } + while (p < pend && *p++ != '\n') { + } + } + if (margin == PY_SSIZE_T_MAX) { + margin = 0; + } + + // Second pass: write cleandoc into buff. + + // copy first line without leading spaces. + p = doc_utf8; + while (*p == ' ') { + p++; + } + if (p == doc_utf8 && margin == 0 ) { + // doc is already clean. + return doc; + } + + char *buff = PyMem_Malloc(doc_size); + char *w = buff; + + while (p < pend) { + int ch = *w++ = *p++; + if (ch == '\n') { + break; + } + } + + // copy subsequent lines without margin. + while (p < pend) { + for (Py_ssize_t i = 0; i < margin; i++, p++) { + if (*p != ' ') { + assert(*p == '\n' || *p == '\0'); + break; + } + } + while (p < pend) { + int ch = *w++ = *p++; + if (ch == '\n') { + break; + } + } + } + + Py_DECREF(doc); + return PyUnicode_FromStringAndSize(buff, w - buff); +} + + PyObject * _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, int optimize, int compile_mode) From 22980dc7c9dcec4b74fea815542601ef582c230e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 15 Jul 2023 09:21:17 -0400 Subject: [PATCH 404/446] gh-106752: Sync with zipp 3.16.2 (#106757) * gh-106752: Sync with zipp 3.16.2 * Add blurb --- .../test_zipfile/_path/test_complexity.py | 81 ++++++++++++++++++- Lib/test/test_zipfile/_path/test_path.py | 70 ++++++++++++++-- Lib/test/test_zipfile/_path/write-alpharep.py | 4 + Lib/zipfile/_path/__init__.py | 31 +++---- Lib/zipfile/_path/glob.py | 40 +++++++++ ...-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst | 5 ++ 6 files changed, 204 insertions(+), 27 deletions(-) create mode 100644 Lib/test/test_zipfile/_path/write-alpharep.py create mode 100644 Lib/zipfile/_path/glob.py create mode 100644 Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst diff --git a/Lib/test/test_zipfile/_path/test_complexity.py b/Lib/test/test_zipfile/_path/test_complexity.py index 3432dc39e56c4e..7050937738af18 100644 --- a/Lib/test/test_zipfile/_path/test_complexity.py +++ b/Lib/test/test_zipfile/_path/test_complexity.py @@ -1,5 +1,9 @@ -import unittest +import io +import itertools +import math +import re import string +import unittest import zipfile from ._functools import compose @@ -9,9 +13,11 @@ big_o = import_or_skip('big_o') +pytest = import_or_skip('pytest') class TestComplexity(unittest.TestCase): + @pytest.mark.flaky def test_implied_dirs_performance(self): best, others = big_o.big_o( compose(consume, zipfile.CompleteDirs._implied_dirs), @@ -22,3 +28,76 @@ def test_implied_dirs_performance(self): min_n=1, ) assert best <= big_o.complexities.Linear + + def make_zip_path(self, depth=1, width=1) -> zipfile.Path: + """ + Construct a Path with width files at every level of depth. + """ + zf = zipfile.ZipFile(io.BytesIO(), mode='w') + pairs = itertools.product(self.make_deep_paths(depth), self.make_names(width)) + for path, name in pairs: + zf.writestr(f"{path}{name}.txt", b'') + zf.filename = "big un.zip" + return zipfile.Path(zf) + + @classmethod + def make_names(cls, width, letters=string.ascii_lowercase): + """ + >>> list(TestComplexity.make_names(2)) + ['a', 'b'] + >>> list(TestComplexity.make_names(30)) + ['aa', 'ab', ..., 'bd'] + """ + # determine how many products are needed to produce width + n_products = math.ceil(math.log(width, len(letters))) + inputs = (letters,) * n_products + combinations = itertools.product(*inputs) + names = map(''.join, combinations) + return itertools.islice(names, width) + + @classmethod + def make_deep_paths(cls, depth): + return map(cls.make_deep_path, range(depth)) + + @classmethod + def make_deep_path(cls, depth): + return ''.join(('d/',) * depth) + + def test_baseline_regex_complexity(self): + best, others = big_o.big_o( + lambda path: re.fullmatch(r'[^/]*\\.txt', path), + self.make_deep_path, + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Constant + + @pytest.mark.flaky + def test_glob_depth(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + self.make_zip_path, + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Quadratic + + @pytest.mark.flaky + def test_glob_width(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + lambda size: self.make_zip_path(width=size), + max_n=100, + min_n=1, + ) + assert best <= big_o.complexities.Linear + + @pytest.mark.flaky + def test_glob_width_and_depth(self): + best, others = big_o.big_o( + lambda path: consume(path.glob('*.txt')), + lambda size: self.make_zip_path(depth=size, width=size), + max_n=10, + min_n=1, + ) + assert best <= big_o.complexities.Linear diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py index aff91e53995875..c66cb3cba69ebd 100644 --- a/Lib/test/test_zipfile/_path/test_path.py +++ b/Lib/test/test_zipfile/_path/test_path.py @@ -41,9 +41,13 @@ def build_alpharep_fixture(): │ ├── d │ │ └── e.txt │ └── f.txt - └── g - └── h - └── i.txt + ├── g + │ └── h + │ └── i.txt + └── j + ├── k.bin + ├── l.baz + └── m.bar This fixture has the following key characteristics: @@ -51,6 +55,7 @@ def build_alpharep_fixture(): - a file two levels deep (b/d/e) - multiple files in a directory (b/c, b/f) - a directory containing only a directory (g/h) + - a directory with files of different extensions (j/klm) "alpha" because it uses alphabet "rep" because it's a representative example @@ -62,6 +67,9 @@ def build_alpharep_fixture(): zf.writestr("b/d/e.txt", b"content of e") zf.writestr("b/f.txt", b"content of f") zf.writestr("g/h/i.txt", b"content of i") + zf.writestr("j/k.bin", b"content of k") + zf.writestr("j/l.baz", b"content of l") + zf.writestr("j/m.bar", b"content of m") zf.filename = "alpharep.zip" return zf @@ -92,7 +100,7 @@ def zipfile_ondisk(self, alpharep): def test_iterdir_and_types(self, alpharep): root = zipfile.Path(alpharep) assert root.is_dir() - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() assert a.is_file() assert b.is_dir() assert g.is_dir() @@ -112,7 +120,7 @@ def test_is_file_missing(self, alpharep): @pass_alpharep def test_iterdir_on_file(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() with self.assertRaises(ValueError): a.iterdir() @@ -127,7 +135,7 @@ def test_subdir_is_dir(self, alpharep): @pass_alpharep def test_open(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() with a.open(encoding="utf-8") as strm: data = strm.read() self.assertEqual(data, "content of a") @@ -229,7 +237,7 @@ def test_open_missing_directory(self): @pass_alpharep def test_read(self, alpharep): root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() assert a.read_text(encoding="utf-8") == "content of a" # Also check positional encoding arg (gh-101144). assert a.read_text("utf-8") == "content of a" @@ -295,7 +303,7 @@ def test_mutability(self, alpharep): reflect that change. """ root = zipfile.Path(alpharep) - a, b, g = root.iterdir() + a, b, g, j = root.iterdir() alpharep.writestr('foo.txt', 'foo') alpharep.writestr('bar/baz.txt', 'baz') assert any(child.name == 'foo.txt' for child in root.iterdir()) @@ -394,6 +402,13 @@ def test_suffixes(self, alpharep): e = root / '.hgrc' assert e.suffixes == [] + @pass_alpharep + def test_suffix_no_filename(self, alpharep): + alpharep.filename = None + root = zipfile.Path(alpharep) + assert root.joinpath('example').suffix == "" + assert root.joinpath('example').suffixes == [] + @pass_alpharep def test_stem(self, alpharep): """ @@ -411,6 +426,8 @@ def test_stem(self, alpharep): d = root / "d" assert d.stem == "d" + assert (root / ".gitignore").stem == ".gitignore" + @pass_alpharep def test_root_parent(self, alpharep): root = zipfile.Path(alpharep) @@ -442,12 +459,49 @@ def test_match_and_glob(self, alpharep): assert not root.match("*.txt") assert list(root.glob("b/c.*")) == [zipfile.Path(alpharep, "b/c.txt")] + assert list(root.glob("b/*.txt")) == [ + zipfile.Path(alpharep, "b/c.txt"), + zipfile.Path(alpharep, "b/f.txt"), + ] + @pass_alpharep + def test_glob_recursive(self, alpharep): + root = zipfile.Path(alpharep) files = root.glob("**/*.txt") assert all(each.match("*.txt") for each in files) assert list(root.glob("**/*.txt")) == list(root.rglob("*.txt")) + @pass_alpharep + def test_glob_subdirs(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("*/i.txt")) == [] + assert list(root.rglob("*/i.txt")) == [zipfile.Path(alpharep, "g/h/i.txt")] + + @pass_alpharep + def test_glob_does_not_overmatch_dot(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("*.xt")) == [] + + @pass_alpharep + def test_glob_single_char(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("a?txt")) == [zipfile.Path(alpharep, "a.txt")] + assert list(root.glob("a[.]txt")) == [zipfile.Path(alpharep, "a.txt")] + assert list(root.glob("a[?]txt")) == [] + + @pass_alpharep + def test_glob_chars(self, alpharep): + root = zipfile.Path(alpharep) + + assert list(root.glob("j/?.b[ai][nz]")) == [ + zipfile.Path(alpharep, "j/k.bin"), + zipfile.Path(alpharep, "j/l.baz"), + ] + def test_glob_empty(self): root = zipfile.Path(zipfile.ZipFile(io.BytesIO(), 'w')) with self.assertRaises(ValueError): diff --git a/Lib/test/test_zipfile/_path/write-alpharep.py b/Lib/test/test_zipfile/_path/write-alpharep.py new file mode 100644 index 00000000000000..48c09b537179fd --- /dev/null +++ b/Lib/test/test_zipfile/_path/write-alpharep.py @@ -0,0 +1,4 @@ +from . import test_path + + +__name__ == '__main__' and test_path.build_alpharep_fixture().extractall('alpharep') diff --git a/Lib/zipfile/_path/__init__.py b/Lib/zipfile/_path/__init__.py index fd49a3ea91db59..78c413563bb2b1 100644 --- a/Lib/zipfile/_path/__init__.py +++ b/Lib/zipfile/_path/__init__.py @@ -5,7 +5,8 @@ import contextlib import pathlib import re -import fnmatch + +from .glob import translate __all__ = ['Path'] @@ -296,21 +297,24 @@ def open(self, mode='r', *args, pwd=None, **kwargs): encoding, args, kwargs = _extract_text_encoding(*args, **kwargs) return io.TextIOWrapper(stream, encoding, *args, **kwargs) + def _base(self): + return pathlib.PurePosixPath(self.at or self.root.filename) + @property def name(self): - return pathlib.Path(self.at).name or self.filename.name + return self._base().name @property def suffix(self): - return pathlib.Path(self.at).suffix or self.filename.suffix + return self._base().suffix @property def suffixes(self): - return pathlib.Path(self.at).suffixes or self.filename.suffixes + return self._base().suffixes @property def stem(self): - return pathlib.Path(self.at).stem or self.filename.stem + return self._base().stem @property def filename(self): @@ -347,7 +351,7 @@ def iterdir(self): return filter(self._is_child, subs) def match(self, path_pattern): - return pathlib.Path(self.at).match(path_pattern) + return pathlib.PurePosixPath(self.at).match(path_pattern) def is_symlink(self): """ @@ -355,22 +359,13 @@ def is_symlink(self): """ return False - def _descendants(self): - for child in self.iterdir(): - yield child - if child.is_dir(): - yield from child._descendants() - def glob(self, pattern): if not pattern: raise ValueError(f"Unacceptable pattern: {pattern!r}") - matches = re.compile(fnmatch.translate(pattern)).fullmatch - return ( - child - for child in self._descendants() - if matches(str(child.relative_to(self))) - ) + prefix = re.escape(self.at) + matches = re.compile(prefix + translate(pattern)).fullmatch + return map(self._next, filter(matches, self.root.namelist())) def rglob(self, pattern): return self.glob(f'**/{pattern}') diff --git a/Lib/zipfile/_path/glob.py b/Lib/zipfile/_path/glob.py new file mode 100644 index 00000000000000..4a2e665e27078a --- /dev/null +++ b/Lib/zipfile/_path/glob.py @@ -0,0 +1,40 @@ +import re + + +def translate(pattern): + r""" + Given a glob pattern, produce a regex that matches it. + + >>> translate('*.txt') + '[^/]*\\.txt' + >>> translate('a?txt') + 'a.txt' + >>> translate('**/*') + '.*/[^/]*' + """ + return ''.join(map(replace, separate(pattern))) + + +def separate(pattern): + """ + Separate out character sets to avoid translating their contents. + + >>> [m.group(0) for m in separate('*.txt')] + ['*.txt'] + >>> [m.group(0) for m in separate('a[?]txt')] + ['a', '[?]', 'txt'] + """ + return re.finditer(r'([^\[]+)|(?P[\[].*?[\]])|([\[][^\]]*$)', pattern) + + +def replace(match): + """ + Perform the replacements for a match from :func:`separate`. + """ + + return match.group('set') or ( + re.escape(match.group(0)) + .replace('\\*\\*', r'.*') + .replace('\\*', r'[^/]*') + .replace('\\?', r'.') + ) diff --git a/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst b/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst new file mode 100644 index 00000000000000..bbc53d76decbc3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-14-16-54-13.gh-issue-106752.BT1Yxw.rst @@ -0,0 +1,5 @@ +Fixed several bugs in zipfile.Path, including: in ``Path.match`, Windows +separators are no longer honored (and never were meant to be); Fixed +``name``/``suffix``/``suffixes``/``stem`` operations when no filename is +present and the Path is not at the root of the zipfile; Reworked glob for +performance and more correct matching behavior. From e2ec0bad67552e27174255db86dda90fc72e6694 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 15 Jul 2023 14:43:09 -0500 Subject: [PATCH 405/446] Add more examples to the recipe docs (GH-106782) Demonstrate that factor() works for large composites and large primes. --- Doc/library/itertools.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index a2d1798a2c6da1..f88525456ff939 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1045,6 +1045,8 @@ The following recipes have a more mathematical flavor: def factor(n): "Prime factors of n." # factor(99) --> 3 3 11 + # factor(1_000_000_000_000_007) --> 47 59 360620266859 + # factor(1_000_000_000_000_403) --> 1000000000000403 for prime in sieve(math.isqrt(n) + 1): while True: quotient, remainder = divmod(n, prime) From d46a42fd8e8915e03cc211ab9163058b6365ab0f Mon Sep 17 00:00:00 2001 From: Mathieu Dupuy Date: Sat, 15 Jul 2023 22:23:10 +0200 Subject: [PATCH 406/446] faq/library: remove outdated section (#105996) --- Doc/faq/library.rst | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst index 597caaa778e1c8..22f7f846d261d8 100644 --- a/Doc/faq/library.rst +++ b/Doc/faq/library.rst @@ -669,41 +669,6 @@ and client-side web systems. A summary of available frameworks is maintained by Paul Boddie at https://wiki.python.org/moin/WebProgramming\ . -Cameron Laird maintains a useful set of pages about Python web technologies at -https://web.archive.org/web/20210224183619/http://phaseit.net/claird/comp.lang.python/web_python. - - -How can I mimic CGI form submission (METHOD=POST)? --------------------------------------------------- - -I would like to retrieve web pages that are the result of POSTing a form. Is -there existing code that would let me do this easily? - -Yes. Here's a simple example that uses :mod:`urllib.request`:: - - #!/usr/local/bin/python - - import urllib.request - - # build the query string - qs = "First=Josephine&MI=Q&Last=Public" - - # connect and send the server a path - req = urllib.request.urlopen('http://www.some-server.out-there' - '/cgi-bin/some-cgi-script', data=qs) - with req: - msg, hdrs = req.read(), req.info() - -Note that in general for percent-encoded POST operations, query strings must be -quoted using :func:`urllib.parse.urlencode`. For example, to send -``name=Guy Steele, Jr.``:: - - >>> import urllib.parse - >>> urllib.parse.urlencode({'name': 'Guy Steele, Jr.'}) - 'name=Guy+Steele%2C+Jr.' - -.. seealso:: :ref:`urllib-howto` for extensive examples. - What module should I use to help with generating HTML? ------------------------------------------------------ From 8c177294899b621fe04ae755abd41b4d319dd4b5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 16 Jul 2023 00:42:58 +0200 Subject: [PATCH 407/446] Docs: Normalize Argument Clinic How-To section capitalization (#106788) --- Doc/howto/clinic.rst | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 4620b4617e3450..0f99cb64994ab2 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -27,7 +27,8 @@ Argument Clinic How-To version of Argument Clinic that ships with the next version of CPython *could* be totally incompatible and break all your code. -The Goals Of Argument Clinic + +The goals of Argument Clinic ============================ Argument Clinic's primary goal @@ -78,7 +79,7 @@ and it should be able to do many interesting and smart things with all the information you give it. -Basic Concepts And Usage +Basic concepts and usage ======================== Argument Clinic ships with CPython; you'll find it in ``Tools/clinic/clinic.py``. @@ -141,7 +142,7 @@ For the sake of clarity, here's the terminology we'll use with Argument Clinic: a block.) -Converting Your First Function +Converting your first function ============================== The best way to get a sense of how Argument Clinic works is to @@ -558,7 +559,8 @@ Let's dive in! Congratulations, you've ported your first function to work with Argument Clinic! -Advanced Topics + +Advanced topics =============== Now that you've had some experience working with Argument Clinic, it's time @@ -636,7 +638,8 @@ after the last argument). Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this will change soon. -Optional Groups + +Optional groups --------------- Some legacy functions have a tricky approach to parsing their arguments: @@ -899,6 +902,7 @@ available. For each converter it'll show you all the parameters it accepts, along with the default value for each parameter. Just run ``Tools/clinic/clinic.py --converters`` to see the full list. + Py_buffer --------- @@ -908,7 +912,6 @@ you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. Argument Clinic generates code that does it for you (in the parsing function). - Advanced converters ------------------- @@ -975,6 +978,7 @@ value called ``NULL`` for just this reason: from Python's perspective it behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. + Expressions specified as default values --------------------------------------- @@ -1032,7 +1036,6 @@ you're not permitted to use: * Tuple/list/set/dict literals. - Using a return converter ------------------------ @@ -1146,6 +1149,7 @@ then modifying it. Cloning is an all-or nothing proposition. Also, the function you are cloning from must have been previously defined in the current file. + Calling Python code ------------------- @@ -1380,6 +1384,7 @@ handle initialization and cleanup. You can see more examples of custom converters in the CPython source tree; grep the C files for the string ``CConverter``. + Writing a custom return converter --------------------------------- @@ -1394,8 +1399,9 @@ write your own return converter, please read ``Tools/clinic/clinic.py``, specifically the implementation of ``CReturnConverter`` and all its subclasses. + METH_O and METH_NOARGS ----------------------------------------------- +---------------------- To convert a function using ``METH_O``, make sure the function's single argument is using the ``object`` converter, and mark the @@ -1415,8 +1421,9 @@ any arguments. You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. + tp_new and tp_init functions ----------------------------------------------- +---------------------------- You can convert ``tp_new`` and ``tp_init`` functions. Just name them ``__new__`` or ``__init__`` as appropriate. Notes: @@ -1437,6 +1444,7 @@ them ``__new__`` or ``__init__`` as appropriate. Notes: (If your function doesn't support keywords, the parsing function generated will throw an exception if it receives any.) + Changing and redirecting Clinic's output ---------------------------------------- @@ -1721,7 +1729,7 @@ the file was not modified by hand before it gets overwritten. The #ifdef trick ----------------------------------------------- +---------------- If you're converting a function that isn't available on all platforms, there's a trick you can use to make life a little easier. The existing @@ -1801,7 +1809,6 @@ Argument Clinic added to your file (it'll be at the very bottom), then move it above the ``PyMethodDef`` structure where that macro is used. - Using Argument Clinic in Python files ------------------------------------- From c02ee4503151105dc892018ebc7f633e7f3f62f8 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 16 Jul 2023 10:26:26 +0300 Subject: [PATCH 408/446] Docs search: Replace jQuery with vanilla JavaScript (#106743) * Replace jQuery with vanilla JavaScript * Switch 'var' to 'const' or 'let' --- Doc/tools/templates/search.html | 74 ++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/Doc/tools/templates/search.html b/Doc/tools/templates/search.html index f2ac2ea0f09873..852974461380f2 100644 --- a/Doc/tools/templates/search.html +++ b/Doc/tools/templates/search.html @@ -1,48 +1,62 @@ {% extends "!search.html" %} {% block extrahead %} {{ super() }} + -{% endblock %} \ No newline at end of file +{% endblock %} From 83bd568d2b57337a91ef046c1f52f9ebb03a7803 Mon Sep 17 00:00:00 2001 From: Simone Rubino Date: Sun, 16 Jul 2023 09:29:58 +0200 Subject: [PATCH 409/446] Doc: devmode: add -Xdev option to example (#106253) --- Doc/library/devmode.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index 977735990ffe92..b2bad48a07e27e 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -198,7 +198,7 @@ descriptor" error when finalizing the file object: .. code-block:: shell-session - $ python script.py + $ python -X dev script.py import os script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'> main() From e58960160fcb4fce63177fcd9ef605f887377767 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Sun, 16 Jul 2023 21:23:54 +0900 Subject: [PATCH 410/446] Doc: fix section levels of devmode doc (#106801) --- Doc/library/devmode.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/devmode.rst b/Doc/library/devmode.rst index b2bad48a07e27e..80ac13b116c1d2 100644 --- a/Doc/library/devmode.rst +++ b/Doc/library/devmode.rst @@ -16,7 +16,7 @@ setting the :envvar:`PYTHONDEVMODE` environment variable to ``1``. See also :ref:`Python debug build `. Effects of the Python Development Mode -====================================== +-------------------------------------- Enabling the Python Development Mode is similar to the following command, but with additional effects described below:: @@ -107,7 +107,7 @@ value can be read from :data:`sys.flags.dev_mode `. ResourceWarning Example -======================= +----------------------- Example of a script counting the number of lines of the text file specified in the command line:: @@ -171,7 +171,7 @@ application more deterministic and more reliable. Bad file descriptor error example -================================= +--------------------------------- Script displaying the first line of itself:: From cc25ca16ee406db936dfbd2337cbd14b12ccc4b7 Mon Sep 17 00:00:00 2001 From: Kevin Diem Date: Sun, 16 Jul 2023 11:16:34 -0400 Subject: [PATCH 411/446] gh-106706: Streamline family syntax in cases generator DSL (#106716) From `family(opname, STRUCTSIZE) = OPNAME + SPEC1 + ... + SPECn;` to `family(OPNAME, STRUCTSIZE) = SPEC1 + ... + SPECn;` --- ...-07-13-12-08-35.gh-issue-106706.29zp8E.rst | 3 ++ Python/bytecodes.c | 39 +++++++------------ Tools/cases_generator/generate_cases.py | 27 +++++++------ .../cases_generator/interpreter_definition.md | 2 +- Tools/cases_generator/test_generator.py | 2 +- 5 files changed, 31 insertions(+), 42 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst b/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst new file mode 100644 index 00000000000000..bbd8e8eddda607 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-07-13-12-08-35.gh-issue-106706.29zp8E.rst @@ -0,0 +1,3 @@ +Change bytecode syntax for families +to remove redundant name matching +pseudo syntax. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3432b027713462..3c3992c068b063 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,8 +284,7 @@ dummy_func( res = Py_IsFalse(value) ? Py_True : Py_False; } - family(to_bool, INLINE_CACHE_ENTRIES_TO_BOOL) = { - TO_BOOL, + family(TO_BOOL, INLINE_CACHE_ENTRIES_TO_BOOL) = { TO_BOOL_ALWAYS_TRUE, TO_BOOL_BOOL, TO_BOOL_INT, @@ -372,8 +371,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - family(binary_op, INLINE_CACHE_ENTRIES_BINARY_OP) = { - BINARY_OP, + family(BINARY_OP, INLINE_CACHE_ENTRIES_BINARY_OP) = { BINARY_OP_MULTIPLY_INT, BINARY_OP_ADD_INT, BINARY_OP_SUBTRACT_INT, @@ -507,8 +505,7 @@ dummy_func( macro(BINARY_OP_INPLACE_ADD_UNICODE) = _GUARD_BOTH_UNICODE + _BINARY_OP_INPLACE_ADD_UNICODE; - family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { - BINARY_SUBSCR, + family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR_DICT, BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_LIST_INT, @@ -643,8 +640,7 @@ dummy_func( ERROR_IF(err, error); } - family(store_subscr, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { - STORE_SUBSCR, + family(STORE_SUBSCR, INLINE_CACHE_ENTRIES_STORE_SUBSCR) = { STORE_SUBSCR_DICT, STORE_SUBSCR_LIST_INT, }; @@ -921,8 +917,7 @@ dummy_func( ERROR_IF(iter == NULL, error); } - family(send, INLINE_CACHE_ENTRIES_SEND) = { - SEND, + family(SEND, INLINE_CACHE_ENTRIES_SEND) = { SEND_GEN, }; @@ -1134,8 +1129,7 @@ dummy_func( } } - family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { - UNPACK_SEQUENCE, + family(UNPACK_SEQUENCE, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { UNPACK_SEQUENCE_TWO_TUPLE, UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_LIST, @@ -1198,8 +1192,7 @@ dummy_func( ERROR_IF(res == 0, error); } - family(store_attr, INLINE_CACHE_ENTRIES_STORE_ATTR) = { - STORE_ATTR, + family(STORE_ATTR, INLINE_CACHE_ENTRIES_STORE_ATTR) = { STORE_ATTR_INSTANCE_VALUE, STORE_ATTR_SLOT, STORE_ATTR_WITH_HINT, @@ -1298,8 +1291,7 @@ dummy_func( macro(LOAD_FROM_DICT_OR_GLOBALS) = _LOAD_FROM_DICT_OR_GLOBALS; - family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { - LOAD_GLOBAL, + family(LOAD_GLOBAL, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = { LOAD_GLOBAL_MODULE, LOAD_GLOBAL_BUILTIN, }; @@ -1647,8 +1639,7 @@ dummy_func( GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); } - family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { - LOAD_SUPER_ATTR, + family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR_ATTR, LOAD_SUPER_ATTR_METHOD, }; @@ -1750,8 +1741,7 @@ dummy_func( } } - family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { - LOAD_ATTR, + family(LOAD_ATTR, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_MODULE, LOAD_ATTR_WITH_HINT, @@ -2048,8 +2038,7 @@ dummy_func( Py_DECREF(owner); } - family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { - COMPARE_OP, + family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = { COMPARE_OP_FLOAT, COMPARE_OP_INT, COMPARE_OP_STR, @@ -2350,8 +2339,7 @@ dummy_func( // This is optimized by skipping that instruction and combining // its effect (popping 'iter' instead of pushing 'next'.) - family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { - FOR_ITER, + family(FOR_ITER, INLINE_CACHE_ENTRIES_FOR_ITER) = { FOR_ITER_LIST, FOR_ITER_TUPLE, FOR_ITER_RANGE, @@ -2810,8 +2798,7 @@ dummy_func( // Cache layout: counter/1, func_version/2 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! - family(call, INLINE_CACHE_ENTRIES_CALL) = { - CALL, + family(CALL, INLINE_CACHE_ENTRIES_CALL) = { CALL_BOUND_METHOD_EXACT_ARGS, CALL_PY_EXACT_ARGS, CALL_PY_WITH_DEFAULTS, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 6589289121863b..3edd8ee51ba64e 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -438,7 +438,7 @@ def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct if family := self.family: - if self.name == family.members[0]: + if self.name == family.name: if cache_size := family.size: out.emit( f"static_assert({cache_size} == " @@ -831,7 +831,7 @@ def find_predictions(self) -> None: def map_families(self) -> None: """Link instruction names back to their family, if they have one.""" for family in self.families.values(): - for member in family.members: + for member in [family.name] + family.members: if member_instr := self.instrs.get(member): if member_instr.family not in (family, None): self.error( @@ -855,8 +855,11 @@ def check_families(self) -> None: - All members must have the same cache, input and output effects """ for family in self.families.values(): - if len(family.members) < 2: - self.error(f"Family {family.name!r} has insufficient members", family) + if family.name not in self.macro_instrs and family.name not in self.instrs: + self.error( + f"Family {family.name!r} has unknown instruction {family.name!r}", + family, + ) members = [ member for member in family.members @@ -867,10 +870,8 @@ def check_families(self) -> None: self.error( f"Family {family.name!r} has unknown members: {unknown}", family ) - if len(members) < 2: - continue - expected_effects = self.effect_counts(members[0]) - for member in members[1:]: + expected_effects = self.effect_counts(family.name) + for member in members: member_effects = self.effect_counts(member) if member_effects != expected_effects: self.error( @@ -1311,11 +1312,10 @@ def write_metadata(self) -> None: self.out.emit("") self.out.emit("_specializations = {") for name, family in self.families.items(): - assert len(family.members) > 1 with self.out.indent(): - self.out.emit(f"\"{family.members[0]}\": [") + self.out.emit(f"\"{family.name}\": [") with self.out.indent(): - for m in family.members[1:]: + for m in family.members: self.out.emit(f"\"{m}\",") self.out.emit(f"],") self.out.emit("}") @@ -1551,9 +1551,8 @@ def write_macro(self, mac: MacroInstruction) -> None: self.out.emit(f"next_instr += {cache_adjust};") if ( - last_instr - and (family := last_instr.family) - and mac.name == family.members[0] + (family := self.families.get(mac.name)) + and mac.name == family.name and (cache_size := family.size) ): self.out.emit( diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md index c03870ef59eb49..f141848631d04a 100644 --- a/Tools/cases_generator/interpreter_definition.md +++ b/Tools/cases_generator/interpreter_definition.md @@ -347,7 +347,7 @@ For explanations see "Generating the interpreter" below.) ### Defining an instruction family -A _family_ represents a specializable instruction and its specializations. +A _family_ maps a specializable instruction to its specializations. Example: These opcodes all share the same instruction format): ```C diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py index e374ac41e6a94d..e44273429b7405 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Tools/cases_generator/test_generator.py @@ -287,7 +287,7 @@ def test_macro_instruction(): inst(OP3, (unused/5, arg2, left, right -- res)) { res = op3(arg2, left, right); } - family(op, INLINE_CACHE_ENTRIES_OP) = { OP, OP3 }; + family(OP, INLINE_CACHE_ENTRIES_OP) = { OP3 }; """ output = """ TARGET(OP1) { From 55408f86d78259f18c56c5e1ea51e0f8dcdbeb67 Mon Sep 17 00:00:00 2001 From: Grigoriev Semyon <33061489+grigoriev-semyon@users.noreply.github.com> Date: Sun, 16 Jul 2023 18:30:39 +0300 Subject: [PATCH 412/446] gh-105726: Add `__slots__` to `AbstractContextManager` and `AbstractAsyncContextManager` (#106771) Co-authored-by: Kumar Aditya --- Lib/contextlib.py | 4 ++++ Lib/test/test_contextlib.py | 10 ++++++++++ Lib/test/test_contextlib_async.py | 12 ++++++++++++ .../2023-07-15-12-52-50.gh-issue-105726.NGthO8.rst | 3 +++ 4 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-07-15-12-52-50.gh-issue-105726.NGthO8.rst diff --git a/Lib/contextlib.py b/Lib/contextlib.py index b5acbcb9e6d77c..95947aceccc304 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -20,6 +20,8 @@ class AbstractContextManager(abc.ABC): __class_getitem__ = classmethod(GenericAlias) + __slots__ = () + def __enter__(self): """Return `self` upon entering the runtime context.""" return self @@ -42,6 +44,8 @@ class AbstractAsyncContextManager(abc.ABC): __class_getitem__ = classmethod(GenericAlias) + __slots__ = () + async def __aenter__(self): """Return `self` upon entering the runtime context.""" return self diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 0f8351ab8108a6..ecc5a43dad43da 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -24,6 +24,16 @@ def __exit__(self, *args): manager = DefaultEnter() self.assertIs(manager.__enter__(), manager) + def test_slots(self): + class DefaultContextManager(AbstractContextManager): + __slots__ = () + + def __exit__(self, *args): + super().__exit__(*args) + + with self.assertRaises(AttributeError): + DefaultContextManager().var = 42 + def test_exit_is_abstract(self): class MissingExit(AbstractContextManager): pass diff --git a/Lib/test/test_contextlib_async.py b/Lib/test/test_contextlib_async.py index 3d43ed0fcab168..bb72ae74e5845f 100644 --- a/Lib/test/test_contextlib_async.py +++ b/Lib/test/test_contextlib_async.py @@ -37,6 +37,18 @@ async def __aexit__(self, *args): async with manager as context: self.assertIs(manager, context) + @_async_test + async def test_slots(self): + class DefaultAsyncContextManager(AbstractAsyncContextManager): + __slots__ = () + + async def __aexit__(self, *args): + await super().__aexit__(*args) + + with self.assertRaises(AttributeError): + manager = DefaultAsyncContextManager() + manager.var = 42 + @_async_test async def test_async_gen_propagates_generator_exit(self): # A regression test for https://bugs.python.org/issue33786. diff --git a/Misc/NEWS.d/next/Library/2023-07-15-12-52-50.gh-issue-105726.NGthO8.rst b/Misc/NEWS.d/next/Library/2023-07-15-12-52-50.gh-issue-105726.NGthO8.rst new file mode 100644 index 00000000000000..434f93240eccdf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-15-12-52-50.gh-issue-105726.NGthO8.rst @@ -0,0 +1,3 @@ +Added ``__slots__`` to :class:`contextlib.AbstractContextManager` and :class:`contextlib.AbstractAsyncContextManager` +so that child classes can use ``__slots__``. + From 4dc593477a2e8a5c22e3e2346aaae05ca46b12cb Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Poupon Date: Sun, 16 Jul 2023 20:14:08 +0300 Subject: [PATCH 413/446] Fix the french used in the email documentation (GH-106279) * Fix the french used in the email documentation The french used in one of the example was either machine translated a while ago or written by someone who does not speak french. Fixed it by using grammatically correct french. --- Doc/includes/email-alternative.py | 10 +++++----- Doc/library/email.examples.rst | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Doc/includes/email-alternative.py b/Doc/includes/email-alternative.py index df7ca6f3faa332..26b302b495c7ac 100644 --- a/Doc/includes/email-alternative.py +++ b/Doc/includes/email-alternative.py @@ -8,14 +8,14 @@ # Create the base text message. msg = EmailMessage() -msg['Subject'] = "Ayons asperges pour le déjeuner" +msg['Subject'] = "Pourquoi pas des asperges pour ce midi ?" msg['From'] = Address("Pepé Le Pew", "pepe", "example.com") msg['To'] = (Address("Penelope Pussycat", "penelope", "example.com"), Address("Fabrette Pussycat", "fabrette", "example.com")) msg.set_content("""\ Salut! -Cela ressemble à un excellent recipie[1] déjeuner. +Cette recette [1] sera sûrement un très bon repas. [1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718 @@ -31,10 +31,10 @@

Salut!

-

Cela ressemble à un excellent +

Cette - recipie - déjeuner. + recette + sera sûrement un très bon repas.

diff --git a/Doc/library/email.examples.rst b/Doc/library/email.examples.rst index fc964622809d0e..492a8354d8bf85 100644 --- a/Doc/library/email.examples.rst +++ b/Doc/library/email.examples.rst @@ -55,11 +55,11 @@ Up to the prompt, the output from the above is: To: Penelope Pussycat , Fabrette Pussycat From: Pepé Le Pew - Subject: Ayons asperges pour le déjeuner + Subject: Pourquoi pas des asperges pour ce midi ? Salut! - Cela ressemble à un excellent recipie[1] déjeuner. + Cette recette [1] sera sûrement un très bon repas. .. rubric:: Footnotes From c41320701b28904064c89a0a29775efed6b6d053 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Mon, 17 Jul 2023 02:05:24 +0300 Subject: [PATCH 414/446] gh-105540: Convert `pytest` tests of `cases_generator` to regular tests (#106713) --- .../test/test_generated_cases.py | 349 ++++++++++-------- Tools/cases_generator/generate_cases.py | 32 +- 2 files changed, 218 insertions(+), 163 deletions(-) rename Tools/cases_generator/test_generator.py => Lib/test/test_generated_cases.py (58%) diff --git a/Tools/cases_generator/test_generator.py b/Lib/test/test_generated_cases.py similarity index 58% rename from Tools/cases_generator/test_generator.py rename to Lib/test/test_generated_cases.py index e44273429b7405..ba0e5e8b0f6954 100644 --- a/Tools/cases_generator/test_generator.py +++ b/Lib/test/test_generated_cases.py @@ -1,97 +1,148 @@ -# Sorry for using pytest, these tests are mostly just for me. -# Use pytest -vv for best results. - import tempfile +import unittest +import os + +from test import test_tools + +test_tools.skip_if_missing('cases_generator') +with test_tools.imports_under_tool('cases_generator'): + import generate_cases + from parser import StackEffect + + +class TestEffects(unittest.TestCase): + def test_effect_sizes(self): + input_effects = [ + x := StackEffect("x", "", "", ""), + y := StackEffect("y", "", "", "oparg"), + z := StackEffect("z", "", "", "oparg*2"), + ] + output_effects = [ + StackEffect("a", "", "", ""), + StackEffect("b", "", "", "oparg*4"), + StackEffect("c", "", "", ""), + ] + other_effects = [ + StackEffect("p", "", "", "oparg<<1"), + StackEffect("q", "", "", ""), + StackEffect("r", "", "", ""), + ] + self.assertEqual(generate_cases.effect_size(x), (1, "")) + self.assertEqual(generate_cases.effect_size(y), (0, "oparg")) + self.assertEqual(generate_cases.effect_size(z), (0, "oparg*2")) + + self.assertEqual( + generate_cases.list_effect_size(input_effects), + (1, "oparg + oparg*2"), + ) + self.assertEqual( + generate_cases.list_effect_size(output_effects), + (2, "oparg*4"), + ) + self.assertEqual( + generate_cases.list_effect_size(other_effects), + (2, "(oparg<<1)"), + ) + + self.assertEqual( + generate_cases.string_effect_size( + generate_cases.list_effect_size(input_effects), + ), "1 + oparg + oparg*2", + ) + self.assertEqual( + generate_cases.string_effect_size( + generate_cases.list_effect_size(output_effects), + ), + "2 + oparg*4", + ) + self.assertEqual( + generate_cases.string_effect_size( + generate_cases.list_effect_size(other_effects), + ), + "2 + (oparg<<1)", + ) + + +class TestGeneratedCases(unittest.TestCase): + def setUp(self) -> None: + super().setUp() -import generate_cases -from parser import StackEffect - - -def test_effect_sizes(): - input_effects = [ - x := StackEffect("x", "", "", ""), - y := StackEffect("y", "", "", "oparg"), - z := StackEffect("z", "", "", "oparg*2"), - ] - output_effects = [ - StackEffect("a", "", "", ""), - StackEffect("b", "", "", "oparg*4"), - StackEffect("c", "", "", ""), - ] - other_effects = [ - StackEffect("p", "", "", "oparg<<1"), - StackEffect("q", "", "", ""), - StackEffect("r", "", "", ""), - ] - assert generate_cases.effect_size(x) == (1, "") - assert generate_cases.effect_size(y) == (0, "oparg") - assert generate_cases.effect_size(z) == (0, "oparg*2") - - assert generate_cases.list_effect_size(input_effects) == (1, "oparg + oparg*2") - assert generate_cases.list_effect_size(output_effects) == (2, "oparg*4") - assert generate_cases.list_effect_size(other_effects) == (2, "(oparg<<1)") - - assert generate_cases.string_effect_size(generate_cases.list_effect_size(input_effects)) == "1 + oparg + oparg*2" - assert generate_cases.string_effect_size(generate_cases.list_effect_size(output_effects)) == "2 + oparg*4" - assert generate_cases.string_effect_size(generate_cases.list_effect_size(other_effects)) == "2 + (oparg<<1)" - - -def run_cases_test(input: str, expected: str): - temp_input = tempfile.NamedTemporaryFile("w+") - temp_input.write(generate_cases.BEGIN_MARKER) - temp_input.write(input) - temp_input.write(generate_cases.END_MARKER) - temp_input.flush() - temp_output = tempfile.NamedTemporaryFile("w+") - temp_metadata = tempfile.NamedTemporaryFile("w+") - temp_pymetadata = tempfile.NamedTemporaryFile("w+") - temp_executor = tempfile.NamedTemporaryFile("w+") - a = generate_cases.Analyzer( - [temp_input.name], - temp_output.name, - temp_metadata.name, - temp_pymetadata.name, - temp_executor.name, - ) - a.parse() - a.analyze() - if a.errors: - raise RuntimeError(f"Found {a.errors} errors") - a.write_instructions() - temp_output.seek(0) - lines = temp_output.readlines() - while lines and lines[0].startswith("// "): - lines.pop(0) - actual = "".join(lines) - # if actual.rstrip() != expected.rstrip(): - # print("Actual:") - # print(actual) - # print("Expected:") - # print(expected) - # print("End") - assert actual.rstrip() == expected.rstrip() - -def test_inst_no_args(): - input = """ + self.temp_dir = tempfile.gettempdir() + self.temp_input_filename = os.path.join(self.temp_dir, "input.txt") + self.temp_output_filename = os.path.join(self.temp_dir, "output.txt") + self.temp_metadata_filename = os.path.join(self.temp_dir, "metadata.txt") + self.temp_pymetadata_filename = os.path.join(self.temp_dir, "pymetadata.txt") + self.temp_executor_filename = os.path.join(self.temp_dir, "executor.txt") + + def tearDown(self) -> None: + for filename in [ + self.temp_input_filename, + self.temp_output_filename, + self.temp_metadata_filename, + self.temp_pymetadata_filename, + self.temp_executor_filename, + ]: + try: + os.remove(filename) + except: + pass + super().tearDown() + + def run_cases_test(self, input: str, expected: str): + with open(self.temp_input_filename, "w+") as temp_input: + temp_input.write(generate_cases.BEGIN_MARKER) + temp_input.write(input) + temp_input.write(generate_cases.END_MARKER) + temp_input.flush() + + a = generate_cases.Analyzer( + [self.temp_input_filename], + self.temp_output_filename, + self.temp_metadata_filename, + self.temp_pymetadata_filename, + self.temp_executor_filename, + ) + a.parse() + a.analyze() + if a.errors: + raise RuntimeError(f"Found {a.errors} errors") + a.write_instructions() + + with open(self.temp_output_filename) as temp_output: + lines = temp_output.readlines() + while lines and lines[0].startswith("// "): + lines.pop(0) + actual = "".join(lines) + # if actual.rstrip() != expected.rstrip(): + # print("Actual:") + # print(actual) + # print("Expected:") + # print(expected) + # print("End") + + self.assertEqual(actual.rstrip(), expected.rstrip()) + + def test_inst_no_args(self): + input = """ inst(OP, (--)) { spam(); } """ - output = """ + output = """ TARGET(OP) { spam(); DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_inst_one_pop(): - input = """ + def test_inst_one_pop(self): + input = """ inst(OP, (value --)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *value = stack_pointer[-1]; spam(); @@ -99,15 +150,15 @@ def test_inst_one_pop(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_inst_one_push(): - input = """ + def test_inst_one_push(self): + input = """ inst(OP, (-- res)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *res; spam(); @@ -116,15 +167,15 @@ def test_inst_one_push(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_inst_one_push_one_pop(): - input = """ + def test_inst_one_push_one_pop(self): + input = """ inst(OP, (value -- res)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *value = stack_pointer[-1]; PyObject *res; @@ -133,15 +184,15 @@ def test_inst_one_push_one_pop(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_binary_op(): - input = """ + def test_binary_op(self): + input = """ inst(OP, (left, right -- res)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -152,15 +203,15 @@ def test_binary_op(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_overlap(): - input = """ + def test_overlap(self): + input = """ inst(OP, (left, right -- left, result)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -170,10 +221,10 @@ def test_overlap(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_predictions_and_eval_breaker(): - input = """ + def test_predictions_and_eval_breaker(self): + input = """ inst(OP1, (--)) { } inst(OP3, (arg -- res)) { @@ -181,7 +232,7 @@ def test_predictions_and_eval_breaker(): CHECK_EVAL_BREAKER(); } """ - output = """ + output = """ TARGET(OP1) { PREDICTED(OP1); DISPATCH(); @@ -196,43 +247,43 @@ def test_predictions_and_eval_breaker(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_error_if_plain(): - input = """ + def test_error_if_plain(self): + input = """ inst(OP, (--)) { ERROR_IF(cond, label); } """ - output = """ + output = """ TARGET(OP) { if (cond) goto label; DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_error_if_plain_with_comment(): - input = """ + def test_error_if_plain_with_comment(self): + input = """ inst(OP, (--)) { ERROR_IF(cond, label); // Comment is ok } """ - output = """ + output = """ TARGET(OP) { if (cond) goto label; DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_error_if_pop(): - input = """ + def test_error_if_pop(self): + input = """ inst(OP, (left, right -- res)) { ERROR_IF(cond, label); } """ - output = """ + output = """ TARGET(OP) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -243,14 +294,14 @@ def test_error_if_pop(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_cache_effect(): - input = """ + def test_cache_effect(self): + input = """ inst(OP, (counter/1, extra/2, value --)) { } """ - output = """ + output = """ TARGET(OP) { PyObject *value = stack_pointer[-1]; uint16_t counter = read_u16(&next_instr[0].cache); @@ -260,23 +311,23 @@ def test_cache_effect(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_suppress_dispatch(): - input = """ + def test_suppress_dispatch(self): + input = """ inst(OP, (--)) { goto somewhere; } """ - output = """ + output = """ TARGET(OP) { goto somewhere; } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_macro_instruction(): - input = """ + def test_macro_instruction(self): + input = """ inst(OP1, (counter/1, left, right -- left, right)) { op1(left, right); } @@ -289,7 +340,7 @@ def test_macro_instruction(): } family(OP, INLINE_CACHE_ENTRIES_OP) = { OP3 }; """ - output = """ + output = """ TARGET(OP1) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -339,15 +390,15 @@ def test_macro_instruction(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_array_input(): - input = """ + def test_array_input(self): + input = """ inst(OP, (below, values[oparg*2], above --)) { spam(); } """ - output = """ + output = """ TARGET(OP) { PyObject *above = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg*2)); @@ -358,15 +409,15 @@ def test_array_input(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_array_output(): - input = """ + def test_array_output(self): + input = """ inst(OP, (unused, unused -- below, values[oparg*3], above)) { spam(values, oparg); } """ - output = """ + output = """ TARGET(OP) { PyObject *below; PyObject **values = stack_pointer - (2) + 1; @@ -378,15 +429,15 @@ def test_array_output(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_array_input_output(): - input = """ + def test_array_input_output(self): + input = """ inst(OP, (values[oparg] -- values[oparg], above)) { spam(values, oparg); } """ - output = """ + output = """ TARGET(OP) { PyObject **values = (stack_pointer - oparg); PyObject *above; @@ -396,15 +447,15 @@ def test_array_input_output(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_array_error_if(): - input = """ + def test_array_error_if(self): + input = """ inst(OP, (extra, values[oparg] --)) { ERROR_IF(oparg == 0, somewhere); } """ - output = """ + output = """ TARGET(OP) { PyObject **values = (stack_pointer - oparg); PyObject *extra = stack_pointer[-(1 + oparg)]; @@ -414,15 +465,15 @@ def test_array_error_if(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_cond_effect(): - input = """ + def test_cond_effect(self): + input = """ inst(OP, (aa, input if ((oparg & 1) == 1), cc -- xx, output if (oparg & 2), zz)) { output = spam(oparg, input); } """ - output = """ + output = """ TARGET(OP) { PyObject *cc = stack_pointer[-1]; PyObject *input = ((oparg & 1) == 1) ? stack_pointer[-(1 + (((oparg & 1) == 1) ? 1 : 0))] : NULL; @@ -439,10 +490,10 @@ def test_cond_effect(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) -def test_macro_cond_effect(): - input = """ + def test_macro_cond_effect(self): + input = """ op(A, (left, middle, right --)) { # Body of A } @@ -451,7 +502,7 @@ def test_macro_cond_effect(): } macro(M) = A + B; """ - output = """ + output = """ TARGET(M) { PyObject *_tmp_1 = stack_pointer[-1]; PyObject *_tmp_2 = stack_pointer[-2]; @@ -479,4 +530,8 @@ def test_macro_cond_effect(): DISPATCH(); } """ - run_cases_test(input, output) + self.run_cases_test(input, output) + + +if __name__ == "__main__": + unittest.main() diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 3edd8ee51ba64e..df5de6e299aaa9 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -156,16 +156,9 @@ def __init__( self.emit_line_directives = emit_line_directives self.comment = comment self.lineno = 1 - filename = os.path.relpath(self.stream.name, ROOT) - # Make filename more user-friendly and less platform-specific - filename = filename.replace("\\", "/") - if filename.startswith("./"): - filename = filename[2:] - if filename.endswith(".new"): - filename = filename[:-4] - self.filename = filename + self.filename = prettify_filename(self.stream.name) self.nominal_lineno = 1 - self.nominal_filename = filename + self.nominal_filename = self.filename def write_raw(self, s: str) -> None: self.stream.write(s) @@ -737,12 +730,8 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() - filename = os.path.relpath(filename, ROOT) - # Make filename more user-friendly and less platform-specific - filename = filename.replace("\\", "/") - if filename.startswith("./"): - filename = filename[2:] - psr = parser.Parser(src, filename=filename) + + psr = parser.Parser(src, filename=prettify_filename(filename)) # Skip until begin marker while tkn := psr.next(raw=True): @@ -1149,7 +1138,7 @@ def write_function( def from_source_files(self) -> str: paths = f"\n{self.out.comment} ".join( - os.path.relpath(filename, ROOT).replace(os.path.sep, posixpath.sep) + prettify_filename(filename) for filename in self.input_filenames ) return f"{self.out.comment} from:\n{self.out.comment} {paths}\n" @@ -1597,6 +1586,17 @@ def wrap_macro(self, mac: MacroInstruction): self.out.emit(f"DISPATCH();") +def prettify_filename(filename: str) -> str: + # Make filename more user-friendly and less platform-specific, + # it is only used for error reporting at this point. + filename = filename.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] + if filename.endswith(".new"): + filename = filename[:-4] + return filename + + def extract_block_text(block: parser.Block) -> tuple[list[str], bool, int]: # Get lines of text with proper dedent blocklines = block.text.splitlines(True) From 383dcbebcda576e3a3fd18c9246364f67bb65df5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 17 Jul 2023 02:04:10 +0200 Subject: [PATCH 415/446] gh-104050: Argument Clinic: Annotate Clinic.parse() (#106760) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 861a6507eae753..9b7069e9b8fcb0 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -42,6 +42,7 @@ Literal, NamedTuple, NoReturn, + Protocol, TypeGuard, overload, ) @@ -2055,7 +2056,12 @@ def write_file(filename: str, new_contents: str) -> None: ClassDict = dict[str, "Class"] DestinationDict = dict[str, Destination] ModuleDict = dict[str, "Module"] -ParserDict = dict[str, "DSLParser"] + + +class Parser(Protocol): + def __init__(self, clinic: Clinic) -> None: ... + def parse(self, block: Block) -> None: ... + clinic = None class Clinic: @@ -2113,7 +2119,7 @@ def __init__( ) -> None: # maps strings to Parser objects. # (instantiated from the "parsers" global.) - self.parsers: ParserDict = {} + self.parsers: dict[str, Parser] = {} self.language: CLanguage = language if printer: fail("Custom printers are broken right now") @@ -2205,7 +2211,7 @@ def get_destination_buffer( d = self.get_destination(name) return d.buffers[item] - def parse(self, input): + def parse(self, input: str) -> str: printer = self.printer self.block_parser = BlockParser(input, self.language, verify=self.verify) for block in self.block_parser: @@ -5521,7 +5527,10 @@ def state_terminal(self, line): # "clinic", handles the Clinic DSL # "python", handles running Python code # -parsers = {'clinic' : DSLParser, 'python': PythonParser} +parsers: dict[str, Callable[[Clinic], Parser]] = { + 'clinic': DSLParser, + 'python': PythonParser, +} clinic = None From 48956cc60ea05bc50b6cd73e53dd9a7d4b1dac9f Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 17 Jul 2023 09:09:11 +0900 Subject: [PATCH 416/446] gh-106797: Remove warning logs from Python/generated_cases.c.h (gh-106798) --- Include/internal/pycore_opcode_metadata.h | 10 +++++----- Python/generated_cases.c.h | 20 ++++++++------------ Tools/cases_generator/generate_cases.py | 14 +++++++++++--- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 8373f56653b1c7..3b2eab23e092ff 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -839,15 +839,15 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case PUSH_EXC_INFO: return 2; case LOAD_ATTR_METHOD_WITH_VALUES: - return (1 ? 1 : 0) + 1; + return 1 + 1; case LOAD_ATTR_METHOD_NO_DICT: - return (1 ? 1 : 0) + 1; + return 1 + 1; case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: - return (0 ? 1 : 0) + 1; + return 0 + 1; case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: - return (0 ? 1 : 0) + 1; + return 0 + 1; case LOAD_ATTR_METHOD_LAZY_DICT: - return (1 ? 1 : 0) + 1; + return 1 + 1; case KW_NAMES: return 0; case INSTRUMENTED_CALL: diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 68531dc074769e..392914c0521e9d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3360,9 +3360,9 @@ res2 = Py_NewRef(descr); assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; - STACK_GROW((1 ? 1 : 0)); + STACK_GROW(1); stack_pointer[-1] = res; - if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } + stack_pointer[-(1 + 1)] = res2; next_instr += 9; DISPATCH(); } @@ -3382,16 +3382,15 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - STACK_GROW((1 ? 1 : 0)); + STACK_GROW(1); stack_pointer[-1] = res; - if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } + stack_pointer[-(1 + 1)] = res2; next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { PyObject *self = stack_pointer[-1]; - PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); @@ -3410,16 +3409,14 @@ assert(descr != NULL); Py_DECREF(self); res = Py_NewRef(descr); - STACK_GROW((0 ? 1 : 0)); + STACK_GROW(0); stack_pointer[-1] = res; - if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { PyObject *self = stack_pointer[-1]; - PyObject *res2 = NULL; PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); @@ -3432,9 +3429,8 @@ assert(descr != NULL); Py_DECREF(self); res = Py_NewRef(descr); - STACK_GROW((0 ? 1 : 0)); + STACK_GROW(0); stack_pointer[-1] = res; - if (0) { stack_pointer[-(1 + (0 ? 1 : 0))] = res2; } next_instr += 9; DISPATCH(); } @@ -3458,9 +3454,9 @@ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); res2 = Py_NewRef(descr); res = self; - STACK_GROW((1 ? 1 : 0)); + STACK_GROW(1); stack_pointer[-1] = res; - if (1) { stack_pointer[-(1 + (1 ? 1 : 0))] = res2; } + stack_pointer[-(1 + 1)] = res2; next_instr += 9; DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index df5de6e299aaa9..a0a8b8cbe4baba 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -98,6 +98,8 @@ def effect_size(effect: StackEffect) -> tuple[int, str]: assert not effect.cond, "Array effects cannot have a condition" return 0, effect.size elif effect.cond: + if effect.cond in ("0", "1"): + return 0, effect.cond return 0, f"{maybe_parenthesize(effect.cond)} ? 1 : 0" else: return 1, "" @@ -217,7 +219,7 @@ def stack_adjust( self.emit(f"STACK_GROW({osym});") def declare(self, dst: StackEffect, src: StackEffect | None): - if dst.name == UNUSED: + if dst.name == UNUSED or dst.cond == "0": return typ = f"{dst.type}" if dst.type else "PyObject *" if src: @@ -241,7 +243,10 @@ def assign(self, dst: StackEffect, src: StackEffect): self.emit(f"Py_XSETREF({dst.name}, {cast}{src.name});") else: stmt = f"{dst.name} = {cast}{src.name};" - if src.cond: + if src.cond and src.cond != "1": + if src.cond == "0": + # It will not be executed + return stmt = f"if ({src.cond}) {{ {stmt} }}" self.emit(stmt) @@ -1067,7 +1072,10 @@ def effect_str(effects: list[StackEffect]) -> str: for effect in comp.instr.output_effects: assert not effect.size, effect if effect.cond: - pushed_symbolic.append(maybe_parenthesize(f"{maybe_parenthesize(effect.cond)} ? 1 : 0")) + if effect.cond in ("0", "1"): + pushed_symbolic.append(effect.cond) + else: + pushed_symbolic.append(maybe_parenthesize(f"{maybe_parenthesize(effect.cond)} ? 1 : 0")) sp += 1 high = max(sp, high) if high != max(0, sp): From babb22da5a25c18a2d203bf72ba35e7861ca60ee Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 16 Jul 2023 21:37:07 -0500 Subject: [PATCH 417/446] Add more recipe tests. Make the factor recipe a bit faster and clearer. (GH-106817) --- Doc/library/itertools.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index f88525456ff939..730736bbb59ed9 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -1049,11 +1049,10 @@ The following recipes have a more mathematical flavor: # factor(1_000_000_000_000_403) --> 1000000000000403 for prime in sieve(math.isqrt(n) + 1): while True: - quotient, remainder = divmod(n, prime) - if remainder: + if n % prime: break yield prime - n = quotient + n //= prime if n == 1: return if n > 1: @@ -1354,6 +1353,12 @@ The following recipes have a more mathematical flavor: >>> set(sieve(10_000)).isdisjoint(carmichael) True + >>> list(factor(99)) # Code example 1 + [3, 3, 11] + >>> list(factor(1_000_000_000_000_007)) # Code example 2 + [47, 59, 360620266859] + >>> list(factor(1_000_000_000_000_403)) # Code example 3 + [1000000000000403] >>> list(factor(0)) [] >>> list(factor(1)) From 7aa89e505d893cd5e6f33b84d66e5fa769089931 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 16 Jul 2023 23:36:03 -0400 Subject: [PATCH 418/446] gh-106780: Add __match_args__ to tutorial example (#106784) Add Point definition with this attribute before example that needs it. --- Doc/tutorial/controlflow.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst index 4336bf50df40a7..e140f51f1dda78 100644 --- a/Doc/tutorial/controlflow.rst +++ b/Doc/tutorial/controlflow.rst @@ -343,7 +343,13 @@ Dotted names (like ``foo.bar``), attribute names (the ``x=`` and ``y=`` above) o (recognized by the "(...)" next to them like ``Point`` above) are never assigned to. Patterns can be arbitrarily nested. For example, if we have a short -list of points, we could match it like this:: +list of Points, with ``__match_args__`` added, we could match it like this:: + + class Point: + __match_args__ = ('x', 'y') + def __init__(self, x, y): + self.x = x + self.y = y match points: case []: From 5ecedbd26692b9fbdd7aad81b991869bf650f929 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:28:33 +0100 Subject: [PATCH 419/446] gh-106789: avoid importing pprint from sysconfig (#106790) --- Lib/opcode.py | 26 +++++-------------- Lib/sysconfig.py | 8 ++++-- ...-07-16-10-40-34.gh-issue-106789.NvyE3C.rst | 1 + 3 files changed, 14 insertions(+), 21 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-16-10-40-34.gh-issue-106789.NvyE3C.rst diff --git a/Lib/opcode.py b/Lib/opcode.py index bc885051c6454e..1b36300785aaea 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -6,26 +6,14 @@ __all__ = ["cmp_op", "hasarg", "hasconst", "hasname", "hasjrel", "hasjabs", "haslocal", "hascompare", "hasfree", "hasexc", "opname", "opmap", - "HAVE_ARGUMENT", "EXTENDED_ARG"] - -# It's a chicken-and-egg I'm afraid: -# We're imported before _opcode's made. -# With exception unheeded -# (stack_effect is not needed) -# Both our chickens and eggs are allayed. -# --Larry Hastings, 2013/11/23 - -try: - from _opcode import stack_effect - __all__.append('stack_effect') -except ImportError: - pass - -# _opcode_metadata may not be ready during early stages of the build -try: + "stack_effect", "HAVE_ARGUMENT", "EXTENDED_ARG"] + +from _opcode import stack_effect + +import sys +# The build uses older versions of Python which do not have _opcode_metadata +if sys.version_info[:2] >= (3, 13): from _opcode_metadata import _specializations, _specialized_instructions -except ModuleNotFoundError: - pass cmp_op = ('<', '<=', '==', '!=', '>', '>=') diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 122d441bd19f5e..a8b5c5f7dfba5b 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -465,10 +465,14 @@ def _get_sysconfigdata_name(): f'_sysconfigdata_{sys.abiflags}_{sys.platform}_{multiarch}', ) +def _print_config_dict(d, stream): + print ("{", file=stream) + for k, v in sorted(d.items()): + print(f" {k!r}: {v!r},", file=stream) + print ("}", file=stream) def _generate_posix_vars(): """Generate the Python module containing build-time variables.""" - import pprint vars = {} # load the installed Makefile: makefile = get_makefile_filename() @@ -523,7 +527,7 @@ def _generate_posix_vars(): f.write('# system configuration generated and used by' ' the sysconfig module\n') f.write('build_time_vars = ') - pprint.pprint(vars, stream=f) + _print_config_dict(vars, stream=f) # Create file used for sys.path fixup -- see Modules/getpath.c with open('pybuilddir.txt', 'w', encoding='utf8') as f: diff --git a/Misc/NEWS.d/next/Library/2023-07-16-10-40-34.gh-issue-106789.NvyE3C.rst b/Misc/NEWS.d/next/Library/2023-07-16-10-40-34.gh-issue-106789.NvyE3C.rst new file mode 100644 index 00000000000000..532f8059740daf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-16-10-40-34.gh-issue-106789.NvyE3C.rst @@ -0,0 +1 @@ +Remove import of :mod:``pprint`` from :mod:``sysconfig``. From 036bb7365607ab7e5cf901f1ac4256f9ae1be82c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 17 Jul 2023 13:47:08 +0200 Subject: [PATCH 420/446] gh-104050: Improve Argument Clinic type annotation coverage (#106810) Add various missing annotations in the following classes: - BlockPrinter - CConverter - CLanguage - FormatCounterFormatter - Language - _TextAccumulator Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 49 ++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 9b7069e9b8fcb0..311f0a1a56a038 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -109,7 +109,7 @@ class _TextAccumulator(NamedTuple): def _text_accumulator() -> _TextAccumulator: text: list[str] = [] - def output(): + def output() -> str: s = ''.join(text) text.clear() return s @@ -433,10 +433,10 @@ class FormatCounterFormatter(string.Formatter): the counts dict would now look like {'a': 2, 'b': 1, 'c': 1} """ - def __init__(self): - self.counts = collections.Counter() + def __init__(self) -> None: + self.counts = collections.Counter[str]() - def get_value(self, key, args, kwargs): + def get_value(self, key: str, args, kwargs) -> str: # type: ignore[override] self.counts[key] += 1 return '' @@ -447,18 +447,25 @@ class Language(metaclass=abc.ABCMeta): stop_line = "" checksum_line = "" - def __init__(self, filename): + def __init__(self, filename: str) -> None: pass @abc.abstractmethod - def render(self, clinic, signatures): + def render( + self, + clinic: Clinic | None, + signatures: Iterable[Module | Class | Function] + ) -> str: pass - def parse_line(self, line): + def parse_line(self, line: str) -> None: pass - def validate(self): - def assert_only_one(attr, *additional_fields): + def validate(self) -> None: + def assert_only_one( + attr: str, + *additional_fields: str + ) -> None: """ Ensures that the string found at getattr(self, attr) contains exactly one formatter replacement string for @@ -485,10 +492,10 @@ def assert_only_one(attr, *additional_fields): """ fields = ['dsl_name'] fields.extend(additional_fields) - line = getattr(self, attr) + line: str = getattr(self, attr) fcf = FormatCounterFormatter() fcf.format(line) - def local_fail(should_be_there_but_isnt): + def local_fail(should_be_there_but_isnt: bool) -> None: if should_be_there_but_isnt: fail("{} {} must contain {{{}}} exactly once!".format( self.__class__.__name__, attr, name)) @@ -749,10 +756,10 @@ class CLanguage(Language): stop_line = "[{dsl_name} start generated code]*/" checksum_line = "/*[{dsl_name} end generated code: {arguments}]*/" - def __init__(self, filename): + def __init__(self, filename: str) -> None: super().__init__(filename) self.cpp = cpp.Monitor(filename) - self.cpp.fail = fail + self.cpp.fail = fail # type: ignore[method-assign] def parse_line(self, line: str) -> None: self.cpp.writeline(line) @@ -935,6 +942,7 @@ def parser_body( add(field) return linear_format(output(), parser_declarations=declarations) + parsearg: str | None if not parameters: parser_code: list[str] | None if not requires_defining_class: @@ -1880,7 +1888,12 @@ class BlockPrinter: language: Language f: io.StringIO = dc.field(default_factory=io.StringIO) - def print_block(self, block, *, core_includes=False): + def print_block( + self, + block: Block, + *, + core_includes: bool = False + ) -> None: input = block.input output = block.output dsl_name = block.dsl_name @@ -1931,7 +1944,7 @@ def print_block(self, block, *, core_includes=False): write(self.language.checksum_line.format(dsl_name=dsl_name, arguments=arguments)) write("\n") - def write(self, text): + def write(self, text: str) -> None: self.f.write(text) @@ -2755,7 +2768,7 @@ class CConverter(metaclass=CConverterAutoRegister): # If not None, should be a string representing a pointer to a # PyTypeObject (e.g. "&PyUnicode_Type"). # Only used by the 'O!' format unit (and the "object" converter). - subclass_of = None + subclass_of: str | None = None # Do we want an adjacent '_length' variable for this variable? # Only used by format units ending with '#'. @@ -2948,7 +2961,7 @@ def simple_declaration(self, by_reference=False, *, in_parser=False): prototype.append(name) return "".join(prototype) - def declaration(self, *, in_parser=False): + def declaration(self, *, in_parser=False) -> str: """ The C statement to declare this variable. """ @@ -3006,7 +3019,7 @@ def pre_render(self): """ pass - def parse_arg(self, argname, displayname): + def parse_arg(self, argname: str, displayname: str): if self.format_unit == 'O&': return """ if (!{converter}({argname}, &{paramname})) {{{{ From ad95c7253a70e559e7d3f25d53f4772f28bb8b44 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 17 Jul 2023 17:55:30 +0200 Subject: [PATCH 421/446] gh-106687: _ssl: use uint64_t for SSL options (#106700) SSL_CTX_get_options() uses uint64_t for options: https://www.openssl.org/docs/man3.1/man3/SSL_CTX_get_options.html Fix this compiler warning on Windows with MSC: conversion from 'uint64_t' to 'long', possible loss of data --- Lib/test/test_ssl.py | 24 +++++++++++++ Modules/_ssl.c | 80 ++++++++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d46ce5e60e2141..6117ca3fdba1b7 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -339,6 +339,15 @@ def test_constants(self): ssl.OP_NO_TLSv1_2 self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23) + def test_options(self): + # gh-106687: SSL options values are unsigned integer (uint64_t) + for name in dir(ssl): + if not name.startswith('OP_'): + continue + with self.subTest(option=name): + value = getattr(ssl, name) + self.assertGreaterEqual(value, 0, f"ssl.{name}") + def test_ssl_types(self): ssl_types = [ _ssl._SSLContext, @@ -951,6 +960,7 @@ def test_get_ciphers(self): ) def test_options(self): + # Test default SSLContext options ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) @@ -959,16 +969,30 @@ def test_options(self): OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) + + # disallow TLSv1 with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) + + # allow TLSv1 with warnings_helper.check_warnings(): ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1) self.assertEqual(default, ctx.options) + + # clear all options ctx.options = 0 # Ubuntu has OP_NO_SSLv3 forced on by default self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3) + # invalid options + with self.assertRaises(OverflowError): + ctx.options = -1 + with self.assertRaises(OverflowError): + ctx.options = 2 ** 100 + with self.assertRaises(TypeError): + ctx.options = "abc" + def test_verify_mode_protocol(self): with warnings_helper.check_warnings(): ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 571de331e92cd9..0cf4d3e9dc8c9b 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3025,7 +3025,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) /*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/ { PySSLContext *self; - long options; + uint64_t options; const SSL_METHOD *method = NULL; SSL_CTX *ctx = NULL; X509_VERIFY_PARAM *params; @@ -3618,20 +3618,32 @@ PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level"); static PyObject * get_options(PySSLContext *self, void *c) { - return PyLong_FromLong(SSL_CTX_get_options(self->ctx)); + uint64_t options = SSL_CTX_get_options(self->ctx); + Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options)); + return PyLong_FromUnsignedLongLong(options); } static int set_options(PySSLContext *self, PyObject *arg, void *c) { - long new_opts, opts, set, clear; - long opt_no = ( + PyObject *new_opts_obj; + unsigned long long new_opts_arg; + uint64_t new_opts, opts, clear, set; + uint64_t opt_no = ( SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3 ); - if (!PyArg_Parse(arg, "l", &new_opts)) + if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) { return -1; + } + new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj); + if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) { + return -1; + } + Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg)); + new_opts = (uint64_t)new_opts_arg; + opts = SSL_CTX_get_options(self->ctx); clear = opts & ~new_opts; set = ~opts & new_opts; @@ -3645,8 +3657,9 @@ set_options(PySSLContext *self, PyObject *arg, void *c) if (clear) { SSL_CTX_clear_options(self->ctx, clear); } - if (set) + if (set) { SSL_CTX_set_options(self->ctx, set); + } return 0; } @@ -5754,10 +5767,24 @@ sslmodule_init_socketapi(PyObject *module) return 0; } + static int -sslmodule_init_constants(PyObject *m) +sslmodule_add_option(PyObject *m, const char *name, uint64_t value) { + Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value)); + PyObject *obj = PyLong_FromUnsignedLongLong(value); + if (obj == NULL) { + return -1; + } + int res = PyModule_AddObjectRef(m, name, obj); + Py_DECREF(obj); + return res; +} + +static int +sslmodule_init_constants(PyObject *m) +{ PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS", PY_SSL_DEFAULT_CIPHER_STRING); @@ -5877,46 +5904,47 @@ sslmodule_init_constants(PyObject *m) PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", PY_SSL_VERSION_TLS1_2); +#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1 + /* protocol options */ - PyModule_AddIntConstant(m, "OP_ALL", - SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); - PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); - PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); - PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); - PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); - PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); + ADD_OPTION("OP_ALL", SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + ADD_OPTION("OP_NO_SSLv2", SSL_OP_NO_SSLv2); + ADD_OPTION("OP_NO_SSLv3", SSL_OP_NO_SSLv3); + ADD_OPTION("OP_NO_TLSv1", SSL_OP_NO_TLSv1); + ADD_OPTION("OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); + ADD_OPTION("OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); #ifdef SSL_OP_NO_TLSv1_3 - PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); + ADD_OPTION("OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); #else - PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0); + ADD_OPTION("OP_NO_TLSv1_3", 0); #endif - PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", + ADD_OPTION("OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); - PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); - PyModule_AddIntConstant(m, "OP_NO_TICKET", SSL_OP_NO_TICKET); - PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT", + ADD_OPTION("OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); + ADD_OPTION("OP_NO_TICKET", SSL_OP_NO_TICKET); + ADD_OPTION("OP_LEGACY_SERVER_CONNECT", SSL_OP_LEGACY_SERVER_CONNECT); #ifdef SSL_OP_SINGLE_ECDH_USE - PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); + ADD_OPTION("OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE); #endif #ifdef SSL_OP_NO_COMPRESSION - PyModule_AddIntConstant(m, "OP_NO_COMPRESSION", + ADD_OPTION("OP_NO_COMPRESSION", SSL_OP_NO_COMPRESSION); #endif #ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT - PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT", + ADD_OPTION("OP_ENABLE_MIDDLEBOX_COMPAT", SSL_OP_ENABLE_MIDDLEBOX_COMPAT); #endif #ifdef SSL_OP_NO_RENEGOTIATION - PyModule_AddIntConstant(m, "OP_NO_RENEGOTIATION", + ADD_OPTION("OP_NO_RENEGOTIATION", SSL_OP_NO_RENEGOTIATION); #endif #ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF", + ADD_OPTION("OP_IGNORE_UNEXPECTED_EOF", SSL_OP_IGNORE_UNEXPECTED_EOF); #endif #ifdef SSL_OP_ENABLE_KTLS - PyModule_AddIntConstant(m, "OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS); + ADD_OPTION("OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS); #endif #ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT From b2b261ab2a2d4ff000c6248dbc52247c78cfa5ab Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 17 Jul 2023 10:06:05 -0700 Subject: [PATCH 422/446] gh-106529: Generate uops for POP_JUMP_IF_[NOT_]NONE (#106796) These aren't automatically translated because (ironically) they are macros deferring to POP_JUMP_IF_{TRUE,FALSE}, which are not viable uops (being manually translated). The hack is that we emit IS_NONE and then set opcode and jump to the POP_JUMP_IF_{TRUE,FALSE} translation code. --- Lib/test/test_capi/test_misc.py | 30 ++++++++++++++++++++++++++++++ Python/optimizer.c | 17 +++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 6df918997b2b19..c0dcff825758ad 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2532,6 +2532,36 @@ def testfunc(n): uops = {opname for opname, _ in ex} self.assertIn("_POP_JUMP_IF_FALSE", uops) + def test_pop_jump_if_none(self): + def testfunc(a): + for x in a: + if x is None: + x = 0 + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc([1, 2, 3]) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("_POP_JUMP_IF_TRUE", uops) + + def test_pop_jump_if_not_none(self): + def testfunc(a): + for x in a: + if x is not None: + x = 0 + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + testfunc([1, 2, 3]) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("_POP_JUMP_IF_FALSE", uops) + def test_pop_jump_if_true(self): def testfunc(n): i = 0 diff --git a/Python/optimizer.c b/Python/optimizer.c index 289b202f806ae1..693ba375971ae7 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -464,9 +464,26 @@ translate_bytecode_to_trace( switch (opcode) { + case POP_JUMP_IF_NONE: + { + RESERVE(2, 2); + ADD_TO_TRACE(IS_NONE, 0); + opcode = POP_JUMP_IF_TRUE; + goto pop_jump_if_bool; + } + + case POP_JUMP_IF_NOT_NONE: + { + RESERVE(2, 2); + ADD_TO_TRACE(IS_NONE, 0); + opcode = POP_JUMP_IF_FALSE; + goto pop_jump_if_bool; + } + case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { +pop_jump_if_bool: // Assume jump unlikely (TODO: handle jump likely case) RESERVE(1, 2); _Py_CODEUNIT *target_instr = From 2b94a05a0e45e4aae030a28b716a038ef529f8ef Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 17 Jul 2023 11:02:58 -0700 Subject: [PATCH 423/446] gh-106581: Add 10 new opcodes by allowing `assert(kwnames == NULL)` (#106707) By turning `assert(kwnames == NULL)` into a macro that is not in the "forbidden" list, many instructions that formerly were skipped because they contained such an assert (but no other mention of `kwnames`) are now supported in Tier 2. This covers 10 instructions in total (all specializations of `CALL` that invoke some C code): - `CALL_NO_KW_TYPE_1` - `CALL_NO_KW_STR_1` - `CALL_NO_KW_TUPLE_1` - `CALL_NO_KW_BUILTIN_O` - `CALL_NO_KW_BUILTIN_FAST` - `CALL_NO_KW_LEN` - `CALL_NO_KW_ISINSTANCE` - `CALL_NO_KW_METHOD_DESCRIPTOR_O` - `CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS` - `CALL_NO_KW_METHOD_DESCRIPTOR_FAST` --- Include/internal/pycore_opcode_metadata.h | 10 + Python/bytecodes.c | 30 +- Python/ceval.c | 4 + Python/ceval_macros.h | 2 + Python/executor_cases.c.h | 329 ++++++++++++++++++++++ Python/generated_cases.c.h | 30 +- Tools/cases_generator/generate_cases.py | 14 +- 7 files changed, 385 insertions(+), 34 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 3b2eab23e092ff..028736e115b3f4 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1309,7 +1309,17 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } }, [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } }, + [CALL_NO_KW_TYPE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TYPE_1, 0, 0 } } }, + [CALL_NO_KW_STR_1] = { .nuops = 1, .uops = { { CALL_NO_KW_STR_1, 0, 0 } } }, + [CALL_NO_KW_TUPLE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TUPLE_1, 0, 0 } } }, [EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { EXIT_INIT_CHECK, 0, 0 } } }, + [CALL_NO_KW_BUILTIN_O] = { .nuops = 1, .uops = { { CALL_NO_KW_BUILTIN_O, 0, 0 } } }, + [CALL_NO_KW_BUILTIN_FAST] = { .nuops = 1, .uops = { { CALL_NO_KW_BUILTIN_FAST, 0, 0 } } }, + [CALL_NO_KW_LEN] = { .nuops = 1, .uops = { { CALL_NO_KW_LEN, 0, 0 } } }, + [CALL_NO_KW_ISINSTANCE] = { .nuops = 1, .uops = { { CALL_NO_KW_ISINSTANCE, 0, 0 } } }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_O, 0, 0 } } }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, 0, 0 } } }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_FAST, 0, 0 } } }, [MAKE_FUNCTION] = { .nuops = 1, .uops = { { MAKE_FUNCTION, 0, 0 } } }, [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { SET_FUNCTION_ATTRIBUTE, 0, 0 } } }, [BUILD_SLICE] = { .nuops = 1, .uops = { { BUILD_SLICE, 0, 0 } } }, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3c3992c068b063..652372cb23dc5e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2776,7 +2776,7 @@ dummy_func( } inst(KW_NAMES, (--)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); } @@ -2927,7 +2927,7 @@ dummy_func( } inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; @@ -2955,7 +2955,7 @@ dummy_func( } inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; @@ -2993,7 +2993,7 @@ dummy_func( } inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -3005,7 +3005,7 @@ dummy_func( } inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -3019,7 +3019,7 @@ dummy_func( } inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); @@ -3038,7 +3038,7 @@ dummy_func( * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) * 3. Pushes the frame for ``__init__`` to the frame stack * */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); _PyCallCache *cache = (_PyCallCache *)next_instr; DEOPT_IF(null != NULL, CALL); DEOPT_IF(!PyType_Check(callable), CALL); @@ -3122,7 +3122,7 @@ dummy_func( inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) { /* Builtin METH_O functions */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3153,7 +3153,7 @@ dummy_func( inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3222,7 +3222,7 @@ dummy_func( } inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); /* len(o) */ int is_meth = method != NULL; int total_args = oparg; @@ -3249,7 +3249,7 @@ dummy_func( } inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ int is_meth = method != NULL; int total_args = oparg; @@ -3279,7 +3279,7 @@ dummy_func( // This is secretly a super-instruction inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -3299,7 +3299,7 @@ dummy_func( } inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3365,7 +3365,7 @@ dummy_func( } inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; int total_args = oparg; @@ -3397,7 +3397,7 @@ dummy_func( } inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { diff --git a/Python/ceval.c b/Python/ceval.c index d6c72fa3ff386c..f13ba9883d9814 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2706,6 +2706,9 @@ void Py_LeaveRecursiveCall(void) ///////////////////// Experimental UOp Interpreter ///////////////////// +#undef ASSERT_KWNAMES_IS_NULL +#define ASSERT_KWNAMES_IS_NULL() (void)0 + #undef DEOPT_IF #define DEOPT_IF(COND, INSTNAME) \ if ((COND)) { \ @@ -2746,6 +2749,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject int opcode; uint64_t operand; int oparg; + for (;;) { opcode = self->trace[pc].opcode; operand = self->trace[pc].operand; diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 72800aaaaa2ac4..874bd45becf0c9 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -349,3 +349,5 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = { [FVC_REPR] = PyObject_Repr, [FVC_ASCII] = PyObject_ASCII }; + +#define ASSERT_KWNAMES_IS_NULL() assert(kwnames == NULL) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index ae21ffad94d801..d85e23b5abb8e6 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1904,6 +1904,68 @@ break; } + case CALL_NO_KW_TYPE_1: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *null = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + assert(oparg == 1); + DEOPT_IF(null != NULL, CALL); + PyObject *obj = args[0]; + DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); + STAT_INC(CALL, hit); + res = Py_NewRef(Py_TYPE(obj)); + Py_DECREF(obj); + Py_DECREF(&PyType_Type); // I.e., callable + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_STR_1: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *null = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + assert(oparg == 1); + DEOPT_IF(null != NULL, CALL); + DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); + STAT_INC(CALL, hit); + PyObject *arg = args[0]; + res = PyObject_Str(arg); + Py_DECREF(arg); + Py_DECREF(&PyUnicode_Type); // I.e., callable + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_TUPLE_1: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *null = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + assert(oparg == 1); + DEOPT_IF(null != NULL, CALL); + DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); + STAT_INC(CALL, hit); + PyObject *arg = args[0]; + res = PySequence_Tuple(arg); + Py_DECREF(arg); + Py_DECREF(&PyTuple_Type); // I.e., tuple + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; assert(STACK_LEVEL() == 2); @@ -1917,6 +1979,273 @@ break; } + case CALL_NO_KW_BUILTIN_O: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + /* Builtin METH_O functions */ + ASSERT_KWNAMES_IS_NULL(); + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + callable = method; + args--; + total_args++; + } + DEOPT_IF(total_args != 1, CALL); + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + PyObject *arg = args[0]; + res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + Py_DECREF(arg); + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_BUILTIN_FAST: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + /* Builtin METH_FASTCALL functions, without keywords */ + ASSERT_KWNAMES_IS_NULL(); + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + callable = method; + args--; + total_args++; + } + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); + /* res = func(self, args, nargs) */ + res = ((_PyCFunctionFast)(void(*)(void))cfunc)( + PyCFunction_GET_SELF(callable), + args, + total_args); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + /* Not deopting because this doesn't mean our optimization was + wrong. `res` can be NULL for valid reasons. Eg. getattr(x, + 'invalid'). In those cases an exception is set, so we must + handle it. + */ + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_LEN: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + /* len(o) */ + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + callable = method; + args--; + total_args++; + } + DEOPT_IF(total_args != 1, CALL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + DEOPT_IF(callable != interp->callable_cache.len, CALL); + STAT_INC(CALL, hit); + PyObject *arg = args[0]; + Py_ssize_t len_i = PyObject_Length(arg); + if (len_i < 0) { + goto error; + } + res = PyLong_FromSsize_t(len_i); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + Py_DECREF(callable); + Py_DECREF(arg); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_ISINSTANCE: { + PyObject **args = (stack_pointer - oparg); + PyObject *callable = stack_pointer[-(1 + oparg)]; + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + /* isinstance(o, o2) */ + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + callable = method; + args--; + total_args++; + } + DEOPT_IF(total_args != 2, CALL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + DEOPT_IF(callable != interp->callable_cache.isinstance, CALL); + STAT_INC(CALL, hit); + PyObject *cls = args[1]; + PyObject *inst = args[0]; + int retval = PyObject_IsInstance(inst, cls); + if (retval < 0) { + goto error; + } + res = PyBool_FromLong(retval); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + Py_DECREF(inst); + Py_DECREF(cls); + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_METHOD_DESCRIPTOR_O: { + PyObject **args = (stack_pointer - oparg); + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + args--; + total_args++; + } + PyMethodDescrObject *callable = + (PyMethodDescrObject *)PEEK(total_args + 1); + DEOPT_IF(total_args != 2, CALL); + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + DEOPT_IF(meth->ml_flags != METH_O, CALL); + PyObject *arg = args[1]; + PyObject *self = args[0]; + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + res = _PyCFunction_TrampolineCall(cfunc, self, arg); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(self); + Py_DECREF(arg); + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: { + PyObject **args = (stack_pointer - oparg); + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + assert(oparg == 0 || oparg == 1); + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + args--; + total_args++; + } + DEOPT_IF(total_args != 1, CALL); + PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + PyObject *self = args[0]; + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + res = _PyCFunction_TrampolineCall(cfunc, self, NULL); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(self); + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: { + PyObject **args = (stack_pointer - oparg); + PyObject *method = stack_pointer[-(2 + oparg)]; + PyObject *res; + ASSERT_KWNAMES_IS_NULL(); + int is_meth = method != NULL; + int total_args = oparg; + if (is_meth) { + args--; + total_args++; + } + PyMethodDescrObject *callable = + (PyMethodDescrObject *)PEEK(total_args + 1); + /* Builtin METH_FASTCALL methods, without keywords */ + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); + PyObject *self = args[0]; + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + STAT_INC(CALL, hit); + _PyCFunctionFast cfunc = + (_PyCFunctionFast)(void(*)(void))meth->ml_meth; + int nargs = total_args - 1; + res = cfunc(self, args + 1, nargs); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + /* Clear the stack of the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 392914c0521e9d..1fd76715dc3e4a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3462,7 +3462,7 @@ } TARGET(KW_NAMES) { - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); DISPATCH(); @@ -3599,7 +3599,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; @@ -3631,7 +3631,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; int argcount = oparg; @@ -3673,7 +3673,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -3694,7 +3694,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -3717,7 +3717,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); @@ -3744,7 +3744,7 @@ * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) * 3. Pushes the frame for ``__init__`` to the frame stack * */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); _PyCallCache *cache = (_PyCallCache *)next_instr; DEOPT_IF(null != NULL, CALL); DEOPT_IF(!PyType_Check(callable), CALL); @@ -3844,7 +3844,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; /* Builtin METH_O functions */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3884,7 +3884,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; /* Builtin METH_FASTCALL functions, without keywords */ - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3971,7 +3971,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); /* len(o) */ int is_meth = method != NULL; int total_args = oparg; @@ -4007,7 +4007,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ int is_meth = method != NULL; int total_args = oparg; @@ -4044,7 +4044,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); assert(method != NULL); PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -4067,7 +4067,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4149,7 +4149,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; int total_args = oparg; @@ -4189,7 +4189,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - assert(kwnames == NULL); + ASSERT_KWNAMES_IS_NULL(); int is_meth = method != NULL; int total_args = oparg; if (is_meth) { diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a0a8b8cbe4baba..112f29a83e4c10 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -408,27 +408,31 @@ def __init__(self, inst: parser.InstDef): def is_viable_uop(self) -> bool: """Whether this instruction is viable as a uop.""" + dprint: typing.Callable[..., None] = lambda *args, **kwargs: None + # if self.name.startswith("CALL"): + # dprint = print + if self.name == "EXIT_TRACE": return True # This has 'return frame' but it's okay if self.always_exits: - # print(f"Skipping {self.name} because it always exits") + dprint(f"Skipping {self.name} because it always exits") return False if self.instr_flags.HAS_ARG_FLAG: # If the instruction uses oparg, it cannot use any caches if self.active_caches: - # print(f"Skipping {self.name} because it uses oparg and caches") + dprint(f"Skipping {self.name} because it uses oparg and caches") return False else: # If it doesn't use oparg, it can have one cache entry if len(self.active_caches) > 1: - # print(f"Skipping {self.name} because it has >1 cache entries") + dprint(f"Skipping {self.name} because it has >1 cache entries") return False res = True for forbidden in FORBIDDEN_NAMES_IN_UOPS: # NOTE: To disallow unspecialized uops, use # if variable_used(self.inst, forbidden): if variable_used_unspecialized(self.inst, forbidden): - # print(f"Skipping {self.name} because it uses {forbidden}") + dprint(f"Skipping {self.name} because it uses {forbidden}") res = False return res @@ -1499,6 +1503,8 @@ def write_executor_instructions(self) -> None: with self.out.block(f"case {thing.name}:"): instr.write(self.out, tier=TIER_TWO) self.out.emit("break;") + # elif instr.kind != "op": + # print(f"NOTE: {thing.name} is not a viable uop") case parser.Macro(): pass case parser.Pseudo(): From 7e96370a946a2ca0f2f25af4ce5b3b59f020721b Mon Sep 17 00:00:00 2001 From: Mario Corchero Date: Mon, 17 Jul 2023 20:57:40 +0200 Subject: [PATCH 424/446] gh-61215: threadingmock: Improve test suite to avoid race conditions (#106822) threadingmock: Improve test suite to avoid race conditions Simplify tests and split them into multiple tests to prevent assertions from triggering race conditions. Additionally, we rely on calling the mocks without delay to validate the functionality of matching calls. --- .../testmock/testthreadingmock.py | 195 ++++++------------ 1 file changed, 58 insertions(+), 137 deletions(-) diff --git a/Lib/test/test_unittest/testmock/testthreadingmock.py b/Lib/test/test_unittest/testmock/testthreadingmock.py index b6e12bcb3cda9c..94e71921d9bc03 100644 --- a/Lib/test/test_unittest/testmock/testthreadingmock.py +++ b/Lib/test/test_unittest/testmock/testthreadingmock.py @@ -8,6 +8,8 @@ threading_helper.requires_working_threading(module=True) +VERY_SHORT_TIMEOUT = 0.1 + class Something: def method_1(self): @@ -93,167 +95,86 @@ def test_no_name_clash(self): waitable_mock.wait_until_called() waitable_mock.wait_until_any_call_with("works") - def test_wait_success(self): + def test_patch(self): waitable_mock = self._make_mock(spec=Something) - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, delay=0.01) - something.method_1.wait_until_called() - something.method_1.wait_until_any_call_with() - something.method_1.assert_called() - - def test_wait_success_with_instance_timeout(self): - waitable_mock = self._make_mock(timeout=1) - - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, delay=0.01) - something.method_1.wait_until_called() - something.method_1.wait_until_any_call_with() - something.method_1.assert_called() - - def test_wait_failed_with_instance_timeout(self): - waitable_mock = self._make_mock(timeout=0.01) - - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, delay=0.5) - self.assertRaises(AssertionError, waitable_mock.method_1.wait_until_called) - self.assertRaises( - AssertionError, waitable_mock.method_1.wait_until_any_call_with - ) - - def test_wait_success_with_timeout_override(self): - waitable_mock = self._make_mock(timeout=0.01) - - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, delay=0.05) - something.method_1.wait_until_called(timeout=1) - - def test_wait_failed_with_timeout_override(self): - waitable_mock = self._make_mock(timeout=1) - - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, delay=0.5) - with self.assertRaises(AssertionError): - something.method_1.wait_until_called(timeout=0.05) - - def test_wait_success_called_before(self): - waitable_mock = self._make_mock() - with patch(f"{__name__}.Something", waitable_mock): something = Something() something.method_1() something.method_1.wait_until_called() - something.method_1.wait_until_any_call_with() - something.method_1.assert_called() - - def test_wait_magic_method(self): - waitable_mock = self._make_mock() - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1.__str__, delay=0.01) - something.method_1.__str__.wait_until_called() - something.method_1.__str__.assert_called() - - def test_wait_until_any_call_with_positional(self): + def test_wait_already_called_success(self): waitable_mock = self._make_mock(spec=Something) + waitable_mock.method_1() + waitable_mock.method_1.wait_until_called() + waitable_mock.method_1.wait_until_any_call_with() + waitable_mock.method_1.assert_called() - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, 1, delay=0.2) - self.assertNotIn(call(1), something.method_1.mock_calls) - self.run_async(something.method_1, 2, delay=0.5) - self.run_async(something.method_1, 3, delay=0.6) - - something.method_1.wait_until_any_call_with(1) - something.method_1.assert_called_with(1) - self.assertNotIn(call(2), something.method_1.mock_calls) - self.assertNotIn(call(3), something.method_1.mock_calls) - - something.method_1.wait_until_any_call_with(3) - self.assertIn(call(2), something.method_1.mock_calls) - something.method_1.wait_until_any_call_with(2) - - def test_wait_until_any_call_with_keywords(self): + def test_wait_until_called_success(self): waitable_mock = self._make_mock(spec=Something) + self.run_async(waitable_mock.method_1, delay=VERY_SHORT_TIMEOUT) + waitable_mock.method_1.wait_until_called() - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - self.run_async(something.method_1, a=1, delay=0.2) - self.assertNotIn(call(a=1), something.method_1.mock_calls) - self.run_async(something.method_1, b=2, delay=0.5) - self.run_async(something.method_1, c=3, delay=0.6) - - something.method_1.wait_until_any_call_with(a=1) - something.method_1.assert_called_with(a=1) - self.assertNotIn(call(b=2), something.method_1.mock_calls) - self.assertNotIn(call(c=3), something.method_1.mock_calls) - - something.method_1.wait_until_any_call_with(c=3) - self.assertIn(call(b=2), something.method_1.mock_calls) - something.method_1.wait_until_any_call_with(b=2) - - def test_wait_until_any_call_with_no_argument_fails_when_called_with_arg(self): - waitable_mock = self._make_mock(timeout=0.01) - - with patch(f"{__name__}.Something", waitable_mock): - something = Something() - something.method_1(1) - - something.method_1.assert_called_with(1) - with self.assertRaises(AssertionError): - something.method_1.wait_until_any_call_with() + def test_wait_until_called_method_timeout(self): + waitable_mock = self._make_mock(spec=Something) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_called(timeout=VERY_SHORT_TIMEOUT) - something.method_1() - something.method_1.wait_until_any_call_with() + def test_wait_until_called_instance_timeout(self): + waitable_mock = self._make_mock(spec=Something, timeout=VERY_SHORT_TIMEOUT) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_called() - def test_wait_until_any_call_with_global_default(self): + def test_wait_until_called_global_timeout(self): with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): - ThreadingMock.DEFAULT_TIMEOUT = 0.01 - m = self._make_mock() + ThreadingMock.DEFAULT_TIMEOUT = VERY_SHORT_TIMEOUT + waitable_mock = self._make_mock(spec=Something) with self.assertRaises(AssertionError): - m.wait_until_any_call_with() - with self.assertRaises(AssertionError): - m.wait_until_called() + waitable_mock.method_1.wait_until_called() - m() - m.wait_until_any_call_with() - assert ThreadingMock.DEFAULT_TIMEOUT != 0.01 + def test_wait_until_any_call_with_success(self): + waitable_mock = self._make_mock() + self.run_async(waitable_mock, delay=VERY_SHORT_TIMEOUT) + waitable_mock.wait_until_any_call_with() - def test_wait_until_any_call_with_change_global_and_override(self): - with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): - ThreadingMock.DEFAULT_TIMEOUT = 0.01 + def test_wait_until_any_call_with_instance_timeout(self): + waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) + with self.assertRaises(AssertionError): + waitable_mock.wait_until_any_call_with() - m1 = self._make_mock() - self.run_async(m1, delay=0.1) + def test_wait_until_any_call_global_timeout(self): + with patch.object(ThreadingMock, "DEFAULT_TIMEOUT"): + ThreadingMock.DEFAULT_TIMEOUT = VERY_SHORT_TIMEOUT + waitable_mock = self._make_mock() with self.assertRaises(AssertionError): - m1.wait_until_called() + waitable_mock.wait_until_any_call_with() - m2 = self._make_mock(timeout=1) - self.run_async(m2, delay=0.1) - m2.wait_until_called() - - m3 = self._make_mock() - self.run_async(m3, delay=0.1) - m3.wait_until_called(timeout=1) - - m4 = self._make_mock() - self.run_async(m4, delay=0.1) - m4.wait_until_called(timeout=None) + def test_wait_until_any_call_positional(self): + waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) + waitable_mock.method_1(1, 2, 3) + waitable_mock.method_1.wait_until_any_call_with(1, 2, 3) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_any_call_with(2, 3, 1) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_any_call_with() - m5 = self._make_mock(timeout=None) - self.run_async(m5, delay=0.1) - m5.wait_until_called() + def test_wait_until_any_call_kw(self): + waitable_mock = self._make_mock(timeout=VERY_SHORT_TIMEOUT) + waitable_mock.method_1(a=1, b=2) + waitable_mock.method_1.wait_until_any_call_with(a=1, b=2) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_any_call_with(a=2, b=1) + with self.assertRaises(AssertionError): + waitable_mock.method_1.wait_until_any_call_with() - assert ThreadingMock.DEFAULT_TIMEOUT != 0.01 + def test_magic_methods_success(self): + waitable_mock = self._make_mock() + str(waitable_mock) + waitable_mock.__str__.wait_until_called() + waitable_mock.__str__.assert_called() def test_reset_mock_resets_wait(self): - m = self._make_mock(timeout=0.01) + m = self._make_mock(timeout=VERY_SHORT_TIMEOUT) with self.assertRaises(AssertionError): m.wait_until_called() From 8e9a1a032233f06ce0f1acdf5f983d614c8745a5 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 17 Jul 2023 12:12:33 -0700 Subject: [PATCH 425/446] gh-106603: Make uop struct a triple (opcode, oparg, operand) (#106794) --- Include/internal/pycore_opcode_metadata.h | 42 +++++++---- Include/internal/pycore_uops.h | 5 +- Lib/test/test_capi/test_misc.py | 24 +++--- Python/bytecodes.c | 16 ++-- Python/ceval.c | 7 +- Python/executor_cases.c.h | 85 +++++++++++++++++++-- Python/generated_cases.c.h | 14 +--- Python/optimizer.c | 91 +++++++++++++---------- Tools/cases_generator/generate_cases.py | 15 +--- 9 files changed, 190 insertions(+), 109 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 028736e115b3f4..c3a0dbb478a7c1 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -38,21 +38,24 @@ #define _SKIP_CACHE 314 #define _GUARD_GLOBALS_VERSION 315 #define _GUARD_BUILTINS_VERSION 316 -#define _GUARD_TYPE_VERSION 317 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 318 -#define IS_NONE 319 -#define _ITER_CHECK_LIST 320 -#define _IS_ITER_EXHAUSTED_LIST 321 -#define _ITER_NEXT_LIST 322 -#define _ITER_CHECK_TUPLE 323 -#define _IS_ITER_EXHAUSTED_TUPLE 324 -#define _ITER_NEXT_TUPLE 325 -#define _ITER_CHECK_RANGE 326 -#define _IS_ITER_EXHAUSTED_RANGE 327 -#define _ITER_NEXT_RANGE 328 -#define _POP_JUMP_IF_FALSE 329 -#define _POP_JUMP_IF_TRUE 330 -#define JUMP_TO_TOP 331 +#define _LOAD_GLOBAL_MODULE 317 +#define _LOAD_GLOBAL_BUILTINS 318 +#define _GUARD_TYPE_VERSION 319 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 320 +#define _LOAD_ATTR_INSTANCE_VALUE 321 +#define IS_NONE 322 +#define _ITER_CHECK_LIST 323 +#define _IS_ITER_EXHAUSTED_LIST 324 +#define _ITER_NEXT_LIST 325 +#define _ITER_CHECK_TUPLE 326 +#define _IS_ITER_EXHAUSTED_TUPLE 327 +#define _ITER_NEXT_TUPLE 328 +#define _ITER_CHECK_RANGE 329 +#define _IS_ITER_EXHAUSTED_RANGE 330 +#define _ITER_NEXT_RANGE 331 +#define _POP_JUMP_IF_FALSE 332 +#define _POP_JUMP_IF_TRUE 333 +#define JUMP_TO_TOP 334 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1245,7 +1248,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, - [STORE_SUBSCR] = { .nuops = 1, .uops = { { STORE_SUBSCR, 1, 0 } } }, + [STORE_SUBSCR] = { .nuops = 1, .uops = { { STORE_SUBSCR, 0, 0 } } }, [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, @@ -1264,6 +1267,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, [UNPACK_EX] = { .nuops = 1, .uops = { { UNPACK_EX, 0, 0 } } }, + [STORE_ATTR] = { .nuops = 1, .uops = { { STORE_ATTR, 0, 0 } } }, [DELETE_ATTR] = { .nuops = 1, .uops = { { DELETE_ATTR, 0, 0 } } }, [STORE_GLOBAL] = { .nuops = 1, .uops = { { STORE_GLOBAL, 0, 0 } } }, [DELETE_GLOBAL] = { .nuops = 1, .uops = { { DELETE_GLOBAL, 0, 0 } } }, @@ -1271,6 +1275,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [LOAD_GLOBAL] = { .nuops = 1, .uops = { { LOAD_GLOBAL, 0, 0 } } }, + [LOAD_GLOBAL_MODULE] = { .nuops = 4, .uops = { { _SKIP_CACHE, 0, 0 }, { _GUARD_GLOBALS_VERSION, 1, 1 }, { _SKIP_CACHE, 0, 0 }, { _LOAD_GLOBAL_MODULE, 1, 3 } } }, + [LOAD_GLOBAL_BUILTIN] = { .nuops = 4, .uops = { { _SKIP_CACHE, 0, 0 }, { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION, 1, 2 }, { _LOAD_GLOBAL_BUILTINS, 1, 3 } } }, [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, @@ -1292,6 +1298,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, + [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _SKIP_CACHE, 0, 0 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } }, [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, @@ -1348,8 +1355,11 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = { [_SKIP_CACHE] = "_SKIP_CACHE", [_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION", [_GUARD_BUILTINS_VERSION] = "_GUARD_BUILTINS_VERSION", + [_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE", + [_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS", [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", + [_LOAD_ATTR_INSTANCE_VALUE] = "_LOAD_ATTR_INSTANCE_VALUE", [IS_NONE] = "IS_NONE", [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", [_IS_ITER_EXHAUSTED_LIST] = "_IS_ITER_EXHAUSTED_LIST", diff --git a/Include/internal/pycore_uops.h b/Include/internal/pycore_uops.h index 5ed275fb857679..edb141cc79f752 100644 --- a/Include/internal/pycore_uops.h +++ b/Include/internal/pycore_uops.h @@ -11,8 +11,9 @@ extern "C" { #define _Py_UOP_MAX_TRACE_LENGTH 32 typedef struct { - int opcode; - uint64_t operand; // Sometimes oparg, sometimes a cache entry + uint32_t opcode; + uint32_t oparg; + uint64_t operand; // A cache entry } _PyUOpInstruction; typedef struct { diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index c0dcff825758ad..4e519fa73c50cc 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2448,7 +2448,7 @@ def testfunc(x): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("SAVE_IP", uops) self.assertIn("LOAD_FAST", uops) @@ -2493,7 +2493,7 @@ def many_vars(): ex = get_first_executor(many_vars) self.assertIsNotNone(ex) - self.assertIn(("LOAD_FAST", 259), list(ex)) + self.assertIn(("LOAD_FAST", 259, 0), list(ex)) def test_unspecialized_unpack(self): # An example of an unspecialized opcode @@ -2514,7 +2514,7 @@ def testfunc(x): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("UNPACK_SEQUENCE", uops) def test_pop_jump_if_false(self): @@ -2529,7 +2529,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_POP_JUMP_IF_FALSE", uops) def test_pop_jump_if_none(self): @@ -2544,7 +2544,7 @@ def testfunc(a): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_POP_JUMP_IF_TRUE", uops) def test_pop_jump_if_not_none(self): @@ -2559,7 +2559,7 @@ def testfunc(a): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_POP_JUMP_IF_FALSE", uops) def test_pop_jump_if_true(self): @@ -2574,7 +2574,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_POP_JUMP_IF_TRUE", uops) def test_jump_backward(self): @@ -2589,7 +2589,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("JUMP_TO_TOP", uops) def test_jump_forward(self): @@ -2609,7 +2609,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} # Since there is no JUMP_FORWARD instruction, # look for indirect evidence: the += operator self.assertIn("_BINARY_OP_ADD_INT", uops) @@ -2630,7 +2630,7 @@ def testfunc(n): self.assertIsNotNone(ex) # for i, (opname, oparg) in enumerate(ex): # print(f"{i:4d}: {opname:<20s} {oparg:3d}") - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_IS_ITER_EXHAUSTED_RANGE", uops) # Verification that the jump goes past END_FOR # is done by manual inspection of the output @@ -2652,7 +2652,7 @@ def testfunc(a): self.assertIsNotNone(ex) # for i, (opname, oparg) in enumerate(ex): # print(f"{i:4d}: {opname:<20s} {oparg:3d}") - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_IS_ITER_EXHAUSTED_LIST", uops) # Verification that the jump goes past END_FOR # is done by manual inspection of the output @@ -2674,7 +2674,7 @@ def testfunc(a): self.assertIsNotNone(ex) # for i, (opname, oparg) in enumerate(ex): # print(f"{i:4d}: {opname:<20s} {oparg:3d}") - uops = {opname for opname, _ in ex} + uops = {opname for opname, _, _ in ex} self.assertIn("_IS_ITER_EXHAUSTED_TUPLE", uops) # Verification that the jump goes past END_FOR # is done by manual inspection of the output diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 652372cb23dc5e..19fb138ee64cba 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -645,18 +645,16 @@ dummy_func( STORE_SUBSCR_LIST_INT, }; - inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) { + inst(STORE_SUBSCR, (unused/1, v, container, sub -- )) { #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_SUBSCR, deferred); - _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); @@ -1198,19 +1196,17 @@ dummy_func( STORE_ATTR_WITH_HINT, }; - inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) { + inst(STORE_ATTR, (unused/1, unused/3, v, owner --)) { #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_ATTR, deferred); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); diff --git a/Python/ceval.c b/Python/ceval.c index f13ba9883d9814..b56ddfb4bd286d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2747,17 +2747,18 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject _Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive; int pc = 0; int opcode; - uint64_t operand; int oparg; + uint64_t operand; for (;;) { opcode = self->trace[pc].opcode; + oparg = self->trace[pc].oparg; operand = self->trace[pc].operand; - oparg = (int)operand; DPRINTF(3, - "%4d: uop %s, operand %" PRIu64 ", stack_level %d\n", + "%4d: uop %s, oparg %d, operand %" PRIu64 ", stack_level %d\n", pc, opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode], + oparg, operand, (int)(stack_pointer - _PyFrame_Stackbase(frame))); pc++; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index d85e23b5abb8e6..f492c1fa9d8e3f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -485,18 +485,15 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; - uint16_t counter = (uint16_t)operand; #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_SUBSCR, deferred); - _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); @@ -849,6 +846,30 @@ break; } + case STORE_ATTR: { + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); + PyObject *owner = stack_pointer[-1]; + PyObject *v = stack_pointer[-2]; + #if ENABLE_SPECIALIZATION + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + next_instr--; + _Py_Specialize_StoreAttr(owner, next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(STORE_ATTR, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); + int err = PyObject_SetAttr(owner, name, v); + Py_DECREF(v); + Py_DECREF(owner); + if (err) goto pop_2_error; + STACK_SHRINK(2); + break; + } + case DELETE_ATTR: { PyObject *owner = stack_pointer[-1]; PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); @@ -1010,6 +1031,42 @@ break; } + case _LOAD_GLOBAL_MODULE: { + PyObject *null = NULL; + PyObject *res; + uint16_t index = (uint16_t)operand; + PyDictObject *dict = (PyDictObject *)GLOBALS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + res = entries[index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } + break; + } + + case _LOAD_GLOBAL_BUILTINS: { + PyObject *null = NULL; + PyObject *res; + uint16_t index = (uint16_t)operand; + PyDictObject *bdict = (PyDictObject *)BUILTINS(); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + res = entries[index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + Py_INCREF(res); + STAT_INC(LOAD_GLOBAL, hit); + null = NULL; + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } + break; + } + case DELETE_FAST: { PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; @@ -1443,6 +1500,24 @@ break; } + case _LOAD_ATTR_INSTANCE_VALUE: { + PyObject *owner = stack_pointer[-1]; + PyObject *res2 = NULL; + PyObject *res; + uint16_t index = (uint16_t)operand; + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + res = _PyDictOrValues_GetValues(dorv)->values[index]; + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + res2 = NULL; + Py_DECREF(owner); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + break; + } + case COMPARE_OP: { static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1fd76715dc3e4a..0148078d18bdc3 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -773,18 +773,15 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; - uint16_t counter = read_u16(&next_instr[0].cache); #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; _Py_Specialize_StoreSubscr(container, sub, next_instr); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_SUBSCR, deferred); - _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); @@ -1437,19 +1434,16 @@ static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; - uint16_t counter = read_u16(&next_instr[0].cache); #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); } STAT_INC(STORE_ATTR, deferred); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, v); diff --git a/Python/optimizer.c b/Python/optimizer.c index 693ba375971ae7..3d385a1506cba3 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -344,13 +344,19 @@ uop_item(_PyUOpExecutorObject *self, Py_ssize_t index) if (oname == NULL) { return NULL; } + PyObject *oparg = PyLong_FromUnsignedLong(self->trace[index].oparg); + if (oparg == NULL) { + Py_DECREF(oname); + return NULL; + } PyObject *operand = PyLong_FromUnsignedLongLong(self->trace[index].operand); if (operand == NULL) { + Py_DECREF(oparg); Py_DECREF(oname); return NULL; } - PyObject *args[2] = { oname, operand }; - return _PyTuple_FromArraySteal(args, 2); + PyObject *args[3] = { oname, oparg, operand }; + return _PyTuple_FromArraySteal(args, 3); } PySequenceMethods uop_as_sequence = { @@ -395,29 +401,33 @@ translate_bytecode_to_trace( #define DPRINTF(level, ...) #endif -#define ADD_TO_TRACE(OPCODE, OPERAND) \ +#define ADD_TO_TRACE(OPCODE, OPARG, OPERAND) \ DPRINTF(2, \ - " ADD_TO_TRACE(%s, %" PRIu64 ")\n", \ + " ADD_TO_TRACE(%s, %d, %" PRIu64 ")\n", \ uop_name(OPCODE), \ + (OPARG), \ (uint64_t)(OPERAND)); \ assert(trace_length < max_length); \ assert(reserved > 0); \ reserved--; \ trace[trace_length].opcode = (OPCODE); \ + trace[trace_length].oparg = (OPARG); \ trace[trace_length].operand = (OPERAND); \ trace_length++; #define INSTR_IP(INSTR, CODE) \ - ((long)((INSTR) - ((_Py_CODEUNIT *)(CODE)->co_code_adaptive))) + ((uint32_t)((INSTR) - ((_Py_CODEUNIT *)(CODE)->co_code_adaptive))) -#define ADD_TO_STUB(INDEX, OPCODE, OPERAND) \ - DPRINTF(2, " ADD_TO_STUB(%d, %s, %" PRIu64 ")\n", \ +#define ADD_TO_STUB(INDEX, OPCODE, OPARG, OPERAND) \ + DPRINTF(2, " ADD_TO_STUB(%d, %s, %d, %" PRIu64 ")\n", \ (INDEX), \ uop_name(OPCODE), \ + (OPARG), \ (uint64_t)(OPERAND)); \ assert(reserved > 0); \ reserved--; \ trace[(INDEX)].opcode = (OPCODE); \ + trace[(INDEX)].oparg = (OPARG); \ trace[(INDEX)].operand = (OPERAND); // Reserve space for n uops @@ -433,7 +443,7 @@ translate_bytecode_to_trace( #define RESERVE(main, stub) RESERVE_RAW((main) + (stub) + 2, uop_name(opcode)) DPRINTF(4, - "Optimizing %s (%s:%d) at byte offset %ld\n", + "Optimizing %s (%s:%d) at byte offset %d\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, @@ -441,11 +451,11 @@ translate_bytecode_to_trace( for (;;) { RESERVE_RAW(2, "epilogue"); // Always need space for SAVE_IP and EXIT_TRACE - ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code)); + ADD_TO_TRACE(SAVE_IP, INSTR_IP(instr, code), 0); - int opcode = instr->op.code; - int oparg = instr->op.arg; - int extras = 0; + uint32_t opcode = instr->op.code; + uint32_t oparg = instr->op.arg; + uint32_t extras = 0; while (opcode == EXTENDED_ARG) { instr++; @@ -467,7 +477,7 @@ translate_bytecode_to_trace( case POP_JUMP_IF_NONE: { RESERVE(2, 2); - ADD_TO_TRACE(IS_NONE, 0); + ADD_TO_TRACE(IS_NONE, 0, 0); opcode = POP_JUMP_IF_TRUE; goto pop_jump_if_bool; } @@ -475,7 +485,7 @@ translate_bytecode_to_trace( case POP_JUMP_IF_NOT_NONE: { RESERVE(2, 2); - ADD_TO_TRACE(IS_NONE, 0); + ADD_TO_TRACE(IS_NONE, 0, 0); opcode = POP_JUMP_IF_FALSE; goto pop_jump_if_bool; } @@ -489,11 +499,11 @@ translate_bytecode_to_trace( _Py_CODEUNIT *target_instr = instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg; max_length -= 2; // Really the start of the stubs - int uopcode = opcode == POP_JUMP_IF_TRUE ? + uint32_t uopcode = opcode == POP_JUMP_IF_TRUE ? _POP_JUMP_IF_TRUE : _POP_JUMP_IF_FALSE; - ADD_TO_TRACE(uopcode, max_length); - ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(target_instr, code)); - ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0); + ADD_TO_TRACE(uopcode, max_length, 0); + ADD_TO_STUB(max_length, SAVE_IP, INSTR_IP(target_instr, code), 0); + ADD_TO_STUB(max_length + 1, EXIT_TRACE, 0, 0); break; } @@ -501,7 +511,7 @@ translate_bytecode_to_trace( { if (instr + 2 - oparg == initial_instr) { RESERVE(1, 0); - ADD_TO_TRACE(JUMP_TO_TOP, 0); + ADD_TO_TRACE(JUMP_TO_TOP, 0, 0); } else { DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n"); @@ -546,14 +556,14 @@ translate_bytecode_to_trace( _Py_CODEUNIT *target_instr = // +1 at the end skips over END_FOR instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg + 1; max_length -= 3; // Really the start of the stubs - ADD_TO_TRACE(check_op, 0); - ADD_TO_TRACE(exhausted_op, 0); - ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length); - ADD_TO_TRACE(next_op, 0); - - ADD_TO_STUB(max_length + 0, POP_TOP, 0); - ADD_TO_STUB(max_length + 1, SAVE_IP, INSTR_IP(target_instr, code)); - ADD_TO_STUB(max_length + 2, EXIT_TRACE, 0); + ADD_TO_TRACE(check_op, 0, 0); + ADD_TO_TRACE(exhausted_op, 0, 0); + ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length, 0); + ADD_TO_TRACE(next_op, 0, 0); + + ADD_TO_STUB(max_length + 0, POP_TOP, 0, 0); + ADD_TO_STUB(max_length + 1, SAVE_IP, INSTR_IP(target_instr, code), 0); + ADD_TO_STUB(max_length + 2, EXIT_TRACE, 0, 0); break; } @@ -564,19 +574,20 @@ translate_bytecode_to_trace( // Reserve space for nuops (+ SAVE_IP + EXIT_TRACE) int nuops = expansion->nuops; RESERVE(nuops, 0); + uint32_t orig_oparg = oparg; // For OPARG_TOP/BOTTOM for (int i = 0; i < nuops; i++) { - uint64_t operand; + oparg = orig_oparg; + uint64_t operand = 0; int offset = expansion->uops[i].offset; switch (expansion->uops[i].size) { case OPARG_FULL: - operand = oparg; if (extras && OPCODE_HAS_JUMP(opcode)) { if (opcode == JUMP_BACKWARD_NO_INTERRUPT) { - operand -= extras; + oparg -= extras; } else { assert(opcode != JUMP_BACKWARD); - operand += extras; + oparg += extras; } } break; @@ -590,10 +601,10 @@ translate_bytecode_to_trace( operand = read_u64(&instr[offset].cache); break; case OPARG_TOP: // First half of super-instr - operand = oparg >> 4; + oparg = orig_oparg >> 4; break; case OPARG_BOTTOM: // Second half of super-instr - operand = oparg & 0xF; + oparg = orig_oparg & 0xF; break; default: fprintf(stderr, @@ -603,7 +614,7 @@ translate_bytecode_to_trace( expansion->uops[i].offset); Py_FatalError("garbled expansion"); } - ADD_TO_TRACE(expansion->uops[i].uop, operand); + ADD_TO_TRACE(expansion->uops[i].uop, oparg, operand); } break; } @@ -621,9 +632,9 @@ translate_bytecode_to_trace( done: // Skip short traces like SAVE_IP, LOAD_FAST, SAVE_IP, EXIT_TRACE if (trace_length > 3) { - ADD_TO_TRACE(EXIT_TRACE, 0); + ADD_TO_TRACE(EXIT_TRACE, 0, 0); DPRINTF(1, - "Created a trace for %s (%s:%d) at byte offset %ld -- length %d\n", + "Created a trace for %s (%s:%d) at byte offset %d -- length %d\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, @@ -644,10 +655,10 @@ translate_bytecode_to_trace( if (trace[i].opcode == _POP_JUMP_IF_FALSE || trace[i].opcode == _POP_JUMP_IF_TRUE) { - uint64_t target = trace[i].operand; - if (target >= (uint64_t)max_length) { + int target = trace[i].oparg; + if (target >= max_length) { target += trace_length - max_length; - trace[i].operand = target; + trace[i].oparg = target; } } } @@ -657,7 +668,7 @@ translate_bytecode_to_trace( } else { DPRINTF(4, - "No trace for %s (%s:%d) at byte offset %ld\n", + "No trace for %s (%s:%d) at byte offset %d\n", PyUnicode_AsUTF8(code->co_qualname), PyUnicode_AsUTF8(code->co_filename), code->co_firstlineno, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 112f29a83e4c10..037bee107cb13a 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -417,16 +417,9 @@ def is_viable_uop(self) -> bool: if self.always_exits: dprint(f"Skipping {self.name} because it always exits") return False - if self.instr_flags.HAS_ARG_FLAG: - # If the instruction uses oparg, it cannot use any caches - if self.active_caches: - dprint(f"Skipping {self.name} because it uses oparg and caches") - return False - else: - # If it doesn't use oparg, it can have one cache entry - if len(self.active_caches) > 1: - dprint(f"Skipping {self.name} because it has >1 cache entries") - return False + if len(self.active_caches) > 1: + # print(f"Skipping {self.name} because it has >1 cache entries") + return False res = True for forbidden in FORBIDDEN_NAMES_IN_UOPS: # NOTE: To disallow unspecialized uops, use @@ -1374,7 +1367,7 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None: if not part.instr.is_viable_uop(): print(f"NOTE: Part {part.instr.name} of {name} is not a viable uop") return - if part.instr.instr_flags.HAS_ARG_FLAG or not part.active_caches: + if not part.active_caches: size, offset = OPARG_SIZES["OPARG_FULL"], 0 else: # If this assert triggers, is_viable_uops() lied From ebf2c56b33553a448da8f60fcd89a622f071b5f4 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Mon, 17 Jul 2023 22:55:40 +0300 Subject: [PATCH 426/446] gh-106831: Fix NULL check of d2i_SSL_SESSION() result in _ssl.c (#106832) --- .../Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst | 2 ++ Modules/_ssl.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst diff --git a/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst b/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst new file mode 100644 index 00000000000000..d3b98626845392 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-17-21-45-15.gh-issue-106831.RqVq9X.rst @@ -0,0 +1,2 @@ +Fix potential missing ``NULL`` check of ``d2i_SSL_SESSION`` result in +``_ssl.c``. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 0cf4d3e9dc8c9b..8612b3dd53924c 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2808,7 +2808,7 @@ _ssl_session_dup(SSL_SESSION *session) { /* get length */ slen = i2d_SSL_SESSION(session, NULL); if (slen == 0 || slen > 0xFF00) { - PyErr_SetString(PyExc_ValueError, "i2d() failed."); + PyErr_SetString(PyExc_ValueError, "i2d() failed"); goto error; } if ((senc = PyMem_Malloc(slen)) == NULL) { @@ -2817,12 +2817,13 @@ _ssl_session_dup(SSL_SESSION *session) { } p = senc; if (!i2d_SSL_SESSION(session, &p)) { - PyErr_SetString(PyExc_ValueError, "i2d() failed."); + PyErr_SetString(PyExc_ValueError, "i2d() failed"); goto error; } const_p = senc; newsession = d2i_SSL_SESSION(NULL, &const_p, slen); - if (session == NULL) { + if (newsession == NULL) { + PyErr_SetString(PyExc_ValueError, "d2i() failed"); goto error; } PyMem_Free(senc); From 22379c60ab8f8b49e75da9bd032a8722af50b409 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Mon, 17 Jul 2023 22:55:10 +0200 Subject: [PATCH 427/446] gh-106368: Increase Argument Clinic test coverage for cpp.Monitor (#106833) --- Lib/test/clinic.test.c | 132 +++++++++++++++++++++++++++++++++++++++- Lib/test/test_clinic.py | 49 +++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/Lib/test/clinic.test.c b/Lib/test/clinic.test.c index 2fd8760415dc72..da99e58c77f021 100644 --- a/Lib/test/clinic.test.c +++ b/Lib/test/clinic.test.c @@ -3726,6 +3726,47 @@ test_preprocessor_guarded_else_impl(PyObject *module) /*[clinic end generated code: output=13af7670aac51b12 input=6657ab31d74c29fc]*/ #endif +#ifndef CONDITION_C +/*[clinic input] +test_preprocessor_guarded_ifndef_condition_c +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_ifndef_condition_c_impl(PyObject *module) +/*[clinic end generated code: output=ed422e8c895bb0a5 input=e9b50491cea2b668]*/ +#else +/*[clinic input] +test_preprocessor_guarded_ifndef_not_condition_c +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_ifndef_not_condition_c_impl(PyObject *module) +/*[clinic end generated code: output=de6f4c6a67f8c536 input=da74e30e01c6f2c5]*/ +#endif + +#if \ +CONDITION_D +/*[clinic input] +test_preprocessor_guarded_if_with_continuation +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_if_with_continuation_impl(PyObject *module) +/*[clinic end generated code: output=3d0712ca9e2d15b9 input=4a956fd91be30284]*/ +#endif + +#if CONDITION_E || CONDITION_F +#warning "different type of CPP directive" +/*[clinic input] +test_preprocessor_guarded_if_e_or_f +Makes sure cpp.Monitor handles other directives than preprocessor conditionals. +[clinic start generated code]*/ + +static PyObject * +test_preprocessor_guarded_if_e_or_f_impl(PyObject *module) +/*[clinic end generated code: output=e49d24ff64ad88bc input=57b9c37f938bc4f1]*/ +#endif + /*[clinic input] dump buffer output pop @@ -3785,6 +3826,79 @@ test_preprocessor_guarded_else(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* !defined(CONDITION_A) && !(CONDITION_B) */ +#if !defined(CONDITION_C) + +PyDoc_STRVAR(test_preprocessor_guarded_ifndef_condition_c__doc__, +"test_preprocessor_guarded_ifndef_condition_c($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF \ + {"test_preprocessor_guarded_ifndef_condition_c", (PyCFunction)test_preprocessor_guarded_ifndef_condition_c, METH_NOARGS, test_preprocessor_guarded_ifndef_condition_c__doc__}, + +static PyObject * +test_preprocessor_guarded_ifndef_condition_c(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_ifndef_condition_c_impl(module); +} + +#endif /* !defined(CONDITION_C) */ + +#if defined(CONDITION_C) + +PyDoc_STRVAR(test_preprocessor_guarded_ifndef_not_condition_c__doc__, +"test_preprocessor_guarded_ifndef_not_condition_c($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF \ + {"test_preprocessor_guarded_ifndef_not_condition_c", (PyCFunction)test_preprocessor_guarded_ifndef_not_condition_c, METH_NOARGS, test_preprocessor_guarded_ifndef_not_condition_c__doc__}, + +static PyObject * +test_preprocessor_guarded_ifndef_not_condition_c(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_ifndef_not_condition_c_impl(module); +} + +#endif /* defined(CONDITION_C) */ + +#if (CONDITION_D) + +PyDoc_STRVAR(test_preprocessor_guarded_if_with_continuation__doc__, +"test_preprocessor_guarded_if_with_continuation($module, /)\n" +"--\n" +"\n"); + +#define TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF \ + {"test_preprocessor_guarded_if_with_continuation", (PyCFunction)test_preprocessor_guarded_if_with_continuation, METH_NOARGS, test_preprocessor_guarded_if_with_continuation__doc__}, + +static PyObject * +test_preprocessor_guarded_if_with_continuation(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_if_with_continuation_impl(module); +} + +#endif /* (CONDITION_D) */ + +#if (CONDITION_E || CONDITION_F) + +PyDoc_STRVAR(test_preprocessor_guarded_if_e_or_f__doc__, +"test_preprocessor_guarded_if_e_or_f($module, /)\n" +"--\n" +"\n" +"Makes sure cpp.Monitor handles other directives than preprocessor conditionals."); + +#define TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF \ + {"test_preprocessor_guarded_if_e_or_f", (PyCFunction)test_preprocessor_guarded_if_e_or_f, METH_NOARGS, test_preprocessor_guarded_if_e_or_f__doc__}, + +static PyObject * +test_preprocessor_guarded_if_e_or_f(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return test_preprocessor_guarded_if_e_or_f_impl(module); +} + +#endif /* (CONDITION_E || CONDITION_F) */ + #ifndef TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF #define TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF #endif /* !defined(TEST_PREPROCESSOR_GUARDED_CONDITION_A_METHODDEF) */ @@ -3796,7 +3910,23 @@ test_preprocessor_guarded_else(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF #define TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF #endif /* !defined(TEST_PREPROCESSOR_GUARDED_ELSE_METHODDEF) */ -/*[clinic end generated code: output=3804bb18d454038c input=3fc80c9989d2f2e1]*/ + +#ifndef TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IFNDEF_CONDITION_C_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IFNDEF_NOT_CONDITION_C_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IF_WITH_CONTINUATION_METHODDEF) */ + +#ifndef TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF + #define TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF +#endif /* !defined(TEST_PREPROCESSOR_GUARDED_IF_E_OR_F_METHODDEF) */ +/*[clinic end generated code: output=fcfae7cac7a99e62 input=3fc80c9989d2f2e1]*/ /*[clinic input] test_vararg_and_posonly diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index b5744f7013d6ad..e925ecca1b9c5d 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -200,6 +200,55 @@ def test_parse_with_body_prefix(self): """).lstrip() # Note, lstrip() because of the newline self.assertEqual(out, expected) + def test_cpp_monitor_fail_nested_block_comment(self): + raw = """ + /* start + /* nested + */ + */ + """ + msg = ( + 'Error in file "test.c" on line 2:\n' + 'Nested block comment!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_invalid_format_noarg(self): + raw = """ + #if + a() + #endif + """ + msg = ( + 'Error in file "test.c" on line 1:\n' + 'Invalid format for #if line: no argument!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_invalid_format_toomanyargs(self): + raw = """ + #ifdef A B + a() + #endif + """ + msg = ( + 'Error in file "test.c" on line 1:\n' + 'Invalid format for #ifdef line: should be exactly one argument!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + + def test_cpp_monitor_fail_no_matching_if(self): + raw = '#else' + msg = ( + 'Error in file "test.c" on line 1:\n' + '#else without matching #if / #ifdef / #ifndef!\n' + ) + out = self.expect_failure(raw) + self.assertEqual(out, msg) + class ClinicGroupPermuterTest(TestCase): def _test(self, l, m, r, output): From 1654916c4864a741507617020453147acf20c9f3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 18 Jul 2023 00:10:03 +0200 Subject: [PATCH 428/446] Add Erlend as CODEOWNER for Argument Clinic docs (#106840) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 234a954cc7662f..882ba9e9c9ebea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -177,3 +177,4 @@ Doc/c-api/stable.rst @encukou # Argument Clinic /Tools/clinic/** @erlend-aasland @AlexWaygood /Lib/test/test_clinic.py @erlend-aasland @AlexWaygood +Doc/howto/clinic.rst @erlend-aasland From 00e52acebd2beb2663202bfc4be0ce79ba77361e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 18 Jul 2023 00:37:11 +0200 Subject: [PATCH 429/446] gh-104683: Argument Clinic: Modernise parse_special_symbol() (#106837) Co-authored-by: Alex Waygood --- Tools/clinic/clinic.py | 136 ++++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 56 deletions(-) diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 311f0a1a56a038..bff8935df13bc6 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -4864,11 +4864,21 @@ def state_parameter(self, line: str | None) -> None: self.parameter_continuation = line[:-1] return - line = line.lstrip() - - if line in ('*', '/', '[', ']'): - self.parse_special_symbol(line) - return + func = self.function + match line.lstrip(): + case '*': + self.parse_star(func) + case '[': + self.parse_opening_square_bracket(func) + case ']': + self.parse_closing_square_bracket(func) + case '/': + self.parse_slash(func) + case param: + self.parse_parameter(param) + + def parse_parameter(self, line: str) -> None: + assert self.function is not None match self.parameter_state: case ParamState.START | ParamState.REQUIRED: @@ -5146,57 +5156,71 @@ def parse_converter( "Annotations must be either a name, a function call, or a string." ) - def parse_special_symbol(self, symbol): - if symbol == '*': - if self.keyword_only: - fail("Function " + self.function.name + " uses '*' more than once.") - self.keyword_only = True - elif symbol == '[': - match self.parameter_state: - case ParamState.START | ParamState.LEFT_SQUARE_BEFORE: - self.parameter_state = ParamState.LEFT_SQUARE_BEFORE - case ParamState.REQUIRED | ParamState.GROUP_AFTER: - self.parameter_state = ParamState.GROUP_AFTER - case st: - fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.b)") - self.group += 1 - self.function.docstring_only = True - elif symbol == ']': - if not self.group: - fail("Function " + self.function.name + " has a ] without a matching [.") - if not any(p.group == self.group for p in self.function.parameters.values()): - fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.") - self.group -= 1 - match self.parameter_state: - case ParamState.LEFT_SQUARE_BEFORE | ParamState.GROUP_BEFORE: - self.parameter_state = ParamState.GROUP_BEFORE - case ParamState.GROUP_AFTER | ParamState.RIGHT_SQUARE_AFTER: - self.parameter_state = ParamState.RIGHT_SQUARE_AFTER - case st: - fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {st}.c)") - elif symbol == '/': - if self.positional_only: - fail("Function " + self.function.name + " uses '/' more than once.") - self.positional_only = True - # REQUIRED and OPTIONAL are allowed here, that allows positional-only without option groups - # to work (and have default values!) - allowed = { - ParamState.REQUIRED, - ParamState.OPTIONAL, - ParamState.RIGHT_SQUARE_AFTER, - ParamState.GROUP_BEFORE, - } - if (self.parameter_state not in allowed) or self.group: - fail(f"Function {self.function.name} has an unsupported group configuration. (Unexpected state {self.parameter_state}.d)") - if self.keyword_only: - fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") - # fixup preceding parameters - for p in self.function.parameters.values(): - if p.is_vararg(): - continue - if (p.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD and not isinstance(p.converter, self_converter)): - fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.") - p.kind = inspect.Parameter.POSITIONAL_ONLY + def parse_star(self, function: Function) -> None: + """Parse keyword-only parameter marker '*'.""" + if self.keyword_only: + fail(f"Function {function.name} uses '*' more than once.") + self.keyword_only = True + + def parse_opening_square_bracket(self, function: Function) -> None: + """Parse opening parameter group symbol '['.""" + match self.parameter_state: + case ParamState.START | ParamState.LEFT_SQUARE_BEFORE: + self.parameter_state = ParamState.LEFT_SQUARE_BEFORE + case ParamState.REQUIRED | ParamState.GROUP_AFTER: + self.parameter_state = ParamState.GROUP_AFTER + case st: + fail(f"Function {function.name} has an unsupported group configuration. " + f"(Unexpected state {st}.b)") + self.group += 1 + function.docstring_only = True + + def parse_closing_square_bracket(self, function: Function) -> None: + """Parse closing parameter group symbol ']'.""" + if not self.group: + fail(f"Function {function.name} has a ] without a matching [.") + if not any(p.group == self.group for p in function.parameters.values()): + fail(f"Function {function.name} has an empty group.\n" + "All groups must contain at least one parameter.") + self.group -= 1 + match self.parameter_state: + case ParamState.LEFT_SQUARE_BEFORE | ParamState.GROUP_BEFORE: + self.parameter_state = ParamState.GROUP_BEFORE + case ParamState.GROUP_AFTER | ParamState.RIGHT_SQUARE_AFTER: + self.parameter_state = ParamState.RIGHT_SQUARE_AFTER + case st: + fail(f"Function {function.name} has an unsupported group configuration. " + f"(Unexpected state {st}.c)") + + def parse_slash(self, function: Function) -> None: + """Parse positional-only parameter marker '/'.""" + if self.positional_only: + fail(f"Function {function.name} uses '/' more than once.") + self.positional_only = True + # REQUIRED and OPTIONAL are allowed here, that allows positional-only + # without option groups to work (and have default values!) + allowed = { + ParamState.REQUIRED, + ParamState.OPTIONAL, + ParamState.RIGHT_SQUARE_AFTER, + ParamState.GROUP_BEFORE, + } + if (self.parameter_state not in allowed) or self.group: + fail(f"Function {function.name} has an unsupported group configuration. " + f"(Unexpected state {self.parameter_state}.d)") + if self.keyword_only: + fail(f"Function {function.name} mixes keyword-only and " + "positional-only parameters, which is unsupported.") + # fixup preceding parameters + for p in function.parameters.values(): + if p.is_vararg(): + continue + if (p.kind is not inspect.Parameter.POSITIONAL_OR_KEYWORD and + not isinstance(p.converter, self_converter) + ): + fail(f"Function {function.name} mixes keyword-only and " + "positional-only parameters, which is unsupported.") + p.kind = inspect.Parameter.POSITIONAL_ONLY def state_parameter_docstring_start(self, line: str | None) -> None: self.parameter_docstring_indent = len(self.indent.margin) From 1e36ca63f9f5e0399efe13a80499cef290314c2a Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 17 Jul 2023 18:30:41 -0700 Subject: [PATCH 430/446] Small fixes to code generator (#106845) These repair nits I found in PR gh-106798 (issue gh-106797) and in PR gh-106716 (issue gh-106706). --- Include/internal/pycore_opcode_metadata.h | 10 +++++----- Python/generated_cases.c.h | 8 +++----- Tools/cases_generator/generate_cases.py | 10 +++++----- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index c3a0dbb478a7c1..a5844b3135d398 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -842,15 +842,15 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case PUSH_EXC_INFO: return 2; case LOAD_ATTR_METHOD_WITH_VALUES: - return 1 + 1; + return 2; case LOAD_ATTR_METHOD_NO_DICT: - return 1 + 1; + return 2; case LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES: - return 0 + 1; + return 1; case LOAD_ATTR_NONDESCRIPTOR_NO_DICT: - return 0 + 1; + return 1; case LOAD_ATTR_METHOD_LAZY_DICT: - return 1 + 1; + return 2; case KW_NAMES: return 0; case INSTRUMENTED_CALL: diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0148078d18bdc3..0a8e4da46b8be3 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3356,7 +3356,7 @@ res = self; STACK_GROW(1); stack_pointer[-1] = res; - stack_pointer[-(1 + 1)] = res2; + stack_pointer[-2] = res2; next_instr += 9; DISPATCH(); } @@ -3378,7 +3378,7 @@ res = self; STACK_GROW(1); stack_pointer[-1] = res; - stack_pointer[-(1 + 1)] = res2; + stack_pointer[-2] = res2; next_instr += 9; DISPATCH(); } @@ -3403,7 +3403,6 @@ assert(descr != NULL); Py_DECREF(self); res = Py_NewRef(descr); - STACK_GROW(0); stack_pointer[-1] = res; next_instr += 9; DISPATCH(); @@ -3423,7 +3422,6 @@ assert(descr != NULL); Py_DECREF(self); res = Py_NewRef(descr); - STACK_GROW(0); stack_pointer[-1] = res; next_instr += 9; DISPATCH(); @@ -3450,7 +3448,7 @@ res = self; STACK_GROW(1); stack_pointer[-1] = res; - stack_pointer[-(1 + 1)] = res2; + stack_pointer[-2] = res2; next_instr += 9; DISPATCH(); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 037bee107cb13a..2713fc6774e845 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -99,7 +99,7 @@ def effect_size(effect: StackEffect) -> tuple[int, str]: return 0, effect.size elif effect.cond: if effect.cond in ("0", "1"): - return 0, effect.cond + return int(effect.cond), "" return 0, f"{maybe_parenthesize(effect.cond)} ? 1 : 0" else: return 1, "" @@ -841,9 +841,9 @@ def map_families(self) -> None: def check_families(self) -> None: """Check each family: - - Must have at least 2 members - - All members must be known instructions - - All members must have the same cache, input and output effects + - Must have at least 2 members (including head) + - Head and all members must be known instructions + - Head and all members must have the same cache, input and output effects """ for family in self.families.values(): if family.name not in self.macro_instrs and family.name not in self.instrs: @@ -868,7 +868,7 @@ def check_families(self) -> None: self.error( f"Family {family.name!r} has inconsistent " f"(cache, input, output) effects:\n" - f" {family.members[0]} = {expected_effects}; " + f" {family.name} = {expected_effects}; " f"{member} = {member_effects}", family, ) From ece3b9d12a2f47da8b144f185dfba9b2b725fc82 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Tue, 18 Jul 2023 12:44:16 +0900 Subject: [PATCH 431/446] gh-106843: fix memleak in _PyCompile_CleanDoc (#106846) --- Python/compile.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index b80f7c01bcd90e..2a735382c0cfda 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2267,6 +2267,7 @@ compiler_function_body(struct compiler *c, stmt_ty s, int is_async, Py_ssize_t f } } if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { + Py_XDECREF(docstring); compiler_exit_scope(c); return ERROR; } @@ -8060,7 +8061,9 @@ _PyCompile_CleanDoc(PyObject *doc) } Py_DECREF(doc); - return PyUnicode_FromStringAndSize(buff, w - buff); + PyObject *res = PyUnicode_FromStringAndSize(buff, w - buff); + PyMem_Free(buff); + return res; } From e1c295e3da9ff5a3eb6b009a1f821d80e564ac87 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 08:56:58 +0300 Subject: [PATCH 432/446] gh-106719: Fix __annotations__ getter and setter in the type and module types (GH-106720) No longer suppress arbitrary errors. Simplify the code. --- ...-07-13-15-59-07.gh-issue-106719.jmVrsv.rst | 2 + Objects/moduleobject.c | 48 ++++++++----------- Objects/typeobject.c | 32 +++++-------- 3 files changed, 35 insertions(+), 47 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst new file mode 100644 index 00000000000000..dc4bef193a3220 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-13-15-59-07.gh-issue-106719.jmVrsv.rst @@ -0,0 +1,2 @@ +No longer suppress arbitrary errors in the ``__annotations__`` getter and +setter in the type and module types. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 4071b5a3f1a62c..ba20534c3bdd8d 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -937,26 +937,20 @@ static PyObject * module_get_annotations(PyModuleObject *m, void *Py_UNUSED(ignored)) { PyObject *dict = PyObject_GetAttr((PyObject *)m, &_Py_ID(__dict__)); - - if ((dict == NULL) || !PyDict_Check(dict)) { + if (dict == NULL) { + return NULL; + } + if (!PyDict_Check(dict)) { PyErr_Format(PyExc_TypeError, ".__dict__ is not a dictionary"); - Py_XDECREF(dict); + Py_DECREF(dict); return NULL; } - PyObject *annotations; - /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ - if (PyDict_Contains(dict, &_Py_ID(__annotations__))) { - annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); - /* - ** _PyDict_GetItemIdWithError could still fail, - ** for instance with a well-timed Ctrl-C or a MemoryError. - ** so let's be totally safe. - */ - if (annotations) { - Py_INCREF(annotations); - } - } else { + PyObject *annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); + if (annotations) { + Py_INCREF(annotations); + } + else if (!PyErr_Occurred()) { annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( @@ -975,8 +969,10 @@ module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignor { int ret = -1; PyObject *dict = PyObject_GetAttr((PyObject *)m, &_Py_ID(__dict__)); - - if ((dict == NULL) || !PyDict_Check(dict)) { + if (dict == NULL) { + return -1; + } + if (!PyDict_Check(dict)) { PyErr_Format(PyExc_TypeError, ".__dict__ is not a dictionary"); goto exit; } @@ -984,19 +980,17 @@ module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignor if (value != NULL) { /* set */ ret = PyDict_SetItem(dict, &_Py_ID(__annotations__), value); - goto exit; } - - /* delete */ - if (!PyDict_Contains(dict, &_Py_ID(__annotations__))) { - PyErr_Format(PyExc_AttributeError, "__annotations__"); - goto exit; + else { + /* delete */ + ret = PyDict_DelItem(dict, &_Py_ID(__annotations__)); + if (ret < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_SetString(PyExc_AttributeError, "__annotations__"); + } } - ret = PyDict_DelItem(dict, &_Py_ID(__annotations__)); - exit: - Py_XDECREF(dict); + Py_DECREF(dict); return ret; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b1f9f1280fd04d..7e5282cabd1bfb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1451,24 +1451,17 @@ type_get_annotations(PyTypeObject *type, void *context) } PyObject *annotations; - /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ PyObject *dict = lookup_tp_dict(type); - if (PyDict_Contains(dict, &_Py_ID(__annotations__))) { - annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); - /* - ** PyDict_GetItemWithError could still fail, - ** for instance with a well-timed Ctrl-C or a MemoryError. - ** so let's be totally safe. - */ - if (annotations) { - if (Py_TYPE(annotations)->tp_descr_get) { - annotations = Py_TYPE(annotations)->tp_descr_get( - annotations, NULL, (PyObject *)type); - } else { - Py_INCREF(annotations); - } + annotations = PyDict_GetItemWithError(dict, &_Py_ID(__annotations__)); + if (annotations) { + if (Py_TYPE(annotations)->tp_descr_get) { + annotations = Py_TYPE(annotations)->tp_descr_get( + annotations, NULL, (PyObject *)type); + } else { + Py_INCREF(annotations); } - } else { + } + else if (!PyErr_Occurred()) { annotations = PyDict_New(); if (annotations) { int result = PyDict_SetItem( @@ -1500,11 +1493,10 @@ type_set_annotations(PyTypeObject *type, PyObject *value, void *context) result = PyDict_SetItem(dict, &_Py_ID(__annotations__), value); } else { /* delete */ - if (!PyDict_Contains(dict, &_Py_ID(__annotations__))) { - PyErr_Format(PyExc_AttributeError, "__annotations__"); - return -1; - } result = PyDict_DelItem(dict, &_Py_ID(__annotations__)); + if (result < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_SetString(PyExc_AttributeError, "__annotations__"); + } } if (result == 0) { From 745492355b94d109e47827e5865846f25ae42d26 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 09:00:22 +0300 Subject: [PATCH 433/446] gh-86493: Fix possible leaks in modules initialization: _curses_panel, _decimal, posix, xxsubtype (GH-106767) --- Modules/_curses_panel.c | 3 +- Modules/_decimal/_decimal.c | 24 +++++++-------- Modules/posixmodule.c | 59 ++++++++++++++----------------------- Modules/xxsubtype.c | 6 ++-- 4 files changed, 37 insertions(+), 55 deletions(-) diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index a3124ff80551e0..292b57c083d0c8 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -662,8 +662,7 @@ _curses_panel_exec(PyObject *mod) state->PyCursesError = PyErr_NewException( "_curses_panel.error", NULL, NULL); - if (PyModule_AddObject(mod, "error", Py_NewRef(state->PyCursesError)) < 0) { - Py_DECREF(state->PyCursesError); + if (PyModule_AddObjectRef(mod, "error", state->PyCursesError) < 0) { return -1; } diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index e3dc304066b45b..f9dc6e875fa5fc 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -5957,7 +5957,7 @@ PyInit__decimal(void) Py_DECREF(base); /* add to module */ - CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); + CHECK_INT(PyModule_AddObjectRef(m, cm->name, cm->ex)); /* add to signal tuple */ PyTuple_SET_ITEM(state->SignalTuple, i, Py_NewRef(cm->ex)); @@ -5986,39 +5986,39 @@ PyInit__decimal(void) ASSIGN_PTR(cm->ex, PyErr_NewException(cm->fqname, base, NULL)); Py_DECREF(base); - CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); + CHECK_INT(PyModule_AddObjectRef(m, cm->name, cm->ex)); } /* Init default context template first */ ASSIGN_PTR(state->default_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); - CHECK_INT(PyModule_AddObject(m, "DefaultContext", - Py_NewRef(state->default_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "DefaultContext", + state->default_context_template)); #ifndef WITH_DECIMAL_CONTEXTVAR ASSIGN_PTR(state->tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); - CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_CONTEXTVAR", Py_False)); #else ASSIGN_PTR(state->current_context_var, PyContextVar_New("decimal_context", NULL)); - CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_CONTEXTVAR", Py_True)); #endif - CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); + CHECK_INT(PyModule_AddObjectRef(m, "HAVE_THREADS", Py_True)); /* Init basic context template */ ASSIGN_PTR(state->basic_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_basic_context(state->basic_context_template); - CHECK_INT(PyModule_AddObject(m, "BasicContext", - Py_NewRef(state->basic_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "BasicContext", + state->basic_context_template)); /* Init extended context template */ ASSIGN_PTR(state->extended_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_extended_context(state->extended_context_template); - CHECK_INT(PyModule_AddObject(m, "ExtendedContext", - Py_NewRef(state->extended_context_template))); + CHECK_INT(PyModule_AddObjectRef(m, "ExtendedContext", + state->extended_context_template)); /* Init mpd_ssize_t constants */ @@ -6037,7 +6037,7 @@ PyInit__decimal(void) /* Init string constants */ for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { ASSIGN_PTR(state->round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); - CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(state->round_map[i]))); + CHECK_INT(PyModule_AddObjectRef(m, mpd_round_string[i], state->round_map[i])); } /* Add specification version number */ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index aef802c232c6ce..fd5e491f4611ee 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16793,57 +16793,49 @@ posixmodule_exec(PyObject *m) if (setup_confname_tables(m)) return -1; - PyModule_AddObject(m, "error", Py_NewRef(PyExc_OSError)); + if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) { + return -1; + } #if defined(HAVE_WAITID) && !defined(__APPLE__) waitid_result_desc.name = MODNAME ".waitid_result"; - PyObject *WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc); - if (WaitidResultType == NULL) { + state->WaitidResultType = (PyObject *)PyStructSequence_NewType(&waitid_result_desc); + if (PyModule_AddObjectRef(m, "waitid_result", state->WaitidResultType) < 0) { return -1; } - PyModule_AddObject(m, "waitid_result", Py_NewRef(WaitidResultType)); - state->WaitidResultType = WaitidResultType; #endif stat_result_desc.name = "os.stat_result"; /* see issue #19209 */ stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; - PyObject *StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc); - if (StatResultType == NULL) { + state->StatResultType = (PyObject *)PyStructSequence_NewType(&stat_result_desc); + if (PyModule_AddObjectRef(m, "stat_result", state->StatResultType) < 0) { return -1; } - PyModule_AddObject(m, "stat_result", Py_NewRef(StatResultType)); - state->StatResultType = StatResultType; - state->statresult_new_orig = ((PyTypeObject *)StatResultType)->tp_new; - ((PyTypeObject *)StatResultType)->tp_new = statresult_new; + state->statresult_new_orig = ((PyTypeObject *)state->StatResultType)->tp_new; + ((PyTypeObject *)state->StatResultType)->tp_new = statresult_new; statvfs_result_desc.name = "os.statvfs_result"; /* see issue #19209 */ - PyObject *StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc); - if (StatVFSResultType == NULL) { + state->StatVFSResultType = (PyObject *)PyStructSequence_NewType(&statvfs_result_desc); + if (PyModule_AddObjectRef(m, "statvfs_result", state->StatVFSResultType) < 0) { return -1; } - PyModule_AddObject(m, "statvfs_result", Py_NewRef(StatVFSResultType)); - state->StatVFSResultType = StatVFSResultType; #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) sched_param_desc.name = MODNAME ".sched_param"; - PyObject *SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc); - if (SchedParamType == NULL) { + state->SchedParamType = (PyObject *)PyStructSequence_NewType(&sched_param_desc); + if (PyModule_AddObjectRef(m, "sched_param", state->SchedParamType) < 0) { return -1; } - PyModule_AddObject(m, "sched_param", Py_NewRef(SchedParamType)); - state->SchedParamType = SchedParamType; - ((PyTypeObject *)SchedParamType)->tp_new = os_sched_param; + ((PyTypeObject *)state->SchedParamType)->tp_new = os_sched_param; #endif /* initialize TerminalSize_info */ - PyObject *TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc); - if (TerminalSizeType == NULL) { + state->TerminalSizeType = (PyObject *)PyStructSequence_NewType(&TerminalSize_desc); + if (PyModule_AddObjectRef(m, "terminal_size", state->TerminalSizeType) < 0) { return -1; } - PyModule_AddObject(m, "terminal_size", Py_NewRef(TerminalSizeType)); - state->TerminalSizeType = TerminalSizeType; /* initialize scandir types */ PyObject *ScandirIteratorType = PyType_FromModuleAndSpec(m, &ScandirIteratorType_spec, NULL); @@ -16852,28 +16844,21 @@ posixmodule_exec(PyObject *m) } state->ScandirIteratorType = ScandirIteratorType; - PyObject *DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL); - if (DirEntryType == NULL) { + state->DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL); + if (PyModule_AddObjectRef(m, "DirEntry", state->DirEntryType) < 0) { return -1; } - PyModule_AddObject(m, "DirEntry", Py_NewRef(DirEntryType)); - state->DirEntryType = DirEntryType; times_result_desc.name = MODNAME ".times_result"; - PyObject *TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc); - if (TimesResultType == NULL) { + state->TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc); + if (PyModule_AddObjectRef(m, "times_result", state->TimesResultType) < 0) { return -1; } - PyModule_AddObject(m, "times_result", Py_NewRef(TimesResultType)); - state->TimesResultType = TimesResultType; - PyTypeObject *UnameResultType = PyStructSequence_NewType(&uname_result_desc); - if (UnameResultType == NULL) { + state->UnameResultType = (PyObject *)PyStructSequence_NewType(&uname_result_desc); + if (PyModule_AddObjectRef(m, "uname_result", state->UnameResultType) < 0) { return -1; } - ; - PyModule_AddObject(m, "uname_result", Py_NewRef(UnameResultType)); - state->UnameResultType = (PyObject *)UnameResultType; if ((state->billion = PyLong_FromLong(1000000000)) == NULL) return -1; diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c index 744ba7bf5d28b6..9e4a3d66ef41bd 100644 --- a/Modules/xxsubtype.c +++ b/Modules/xxsubtype.c @@ -274,12 +274,10 @@ xxsubtype_exec(PyObject* m) if (PyType_Ready(&spamdict_type) < 0) return -1; - if (PyModule_AddObject(m, "spamlist", - Py_NewRef(&spamlist_type)) < 0) + if (PyModule_AddObjectRef(m, "spamlist", (PyObject *)&spamlist_type) < 0) return -1; - if (PyModule_AddObject(m, "spamdict", - Py_NewRef(&spamdict_type)) < 0) + if (PyModule_AddObjectRef(m, "spamdict", (PyObject *)&spamdict_type) < 0) return -1; return 0; } From 83ac1284909433f3f77c0a4f459996b1ba3f1a4d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 09:42:05 +0300 Subject: [PATCH 434/446] bpo-42327: C API: Add PyModule_Add() function (GH-23443) It is a fixed implementation of PyModule_AddObject() which consistently steals reference both on success and on failure. --- Doc/c-api/module.rst | 65 +++++++++---------- Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.13.rst | 5 ++ Include/modsupport.h | 12 +++- Lib/test/test_stable_abi_ctypes.py | 1 + .../2020-11-11-22-36-29.bpo-42327.ODSZBM.rst | 1 + Misc/stable_abi.toml | 2 + PC/python3dll.c | 1 + Python/modsupport.c | 29 +++------ 9 files changed, 61 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 230b471d473be7..d35b302fce6aa6 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -486,12 +486,29 @@ state: .. versionadded:: 3.10 +.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value) + + Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference + to *value*. + It can be called with a result of function that returns a new reference + without bothering to check its result or even saving it to a variable. + + Example usage:: + + if (PyModule_Add(module, "spam", PyBytes_FromString(value)) < 0) { + goto error; + } + + .. versionadded:: 3.13 + + .. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value) Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to *value* on success (if it returns ``0``). - The new :c:func:`PyModule_AddObjectRef` function is recommended, since it is + The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef` + functions are recommended, since it is easy to introduce reference leaks by misusing the :c:func:`PyModule_AddObject` function. @@ -501,44 +518,24 @@ state: only decrements the reference count of *value* **on success**. This means that its return value must be checked, and calling code must - :c:func:`Py_DECREF` *value* manually on error. + :c:func:`Py_XDECREF` *value* manually on error. Example usage:: - static int - add_spam(PyObject *module, int value) - { - PyObject *obj = PyLong_FromLong(value); - if (obj == NULL) { - return -1; - } - if (PyModule_AddObject(module, "spam", obj) < 0) { - Py_DECREF(obj); - return -1; - } - // PyModule_AddObject() stole a reference to obj: - // Py_DECREF(obj) is not needed here - return 0; - } - - The example can also be written without checking explicitly if *obj* is - ``NULL``:: + PyObject *obj = PyBytes_FromString(value); + if (PyModule_AddObject(module, "spam", obj) < 0) { + // If 'obj' is not NULL and PyModule_AddObject() failed, + // 'obj' strong reference must be deleted with Py_XDECREF(). + // If 'obj' is NULL, Py_XDECREF() does nothing. + Py_XDECREF(obj); + goto error; + } + // PyModule_AddObject() stole a reference to obj: + // Py_XDECREF(obj) is not needed here. - static int - add_spam(PyObject *module, int value) - { - PyObject *obj = PyLong_FromLong(value); - if (PyModule_AddObject(module, "spam", obj) < 0) { - Py_XDECREF(obj); - return -1; - } - // PyModule_AddObject() stole a reference to obj: - // Py_DECREF(obj) is not needed here - return 0; - } + .. deprecated:: 3.13 - Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in - this case, since *obj* can be ``NULL``. + :c:func:`PyModule_AddObject` is :term:`soft deprecated`. .. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index e3dd3dab27a035..aa1edf54637058 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -399,6 +399,7 @@ type,PyModuleDef,3.2,,full-abi type,PyModuleDef_Base,3.2,,full-abi function,PyModuleDef_Init,3.5,, var,PyModuleDef_Type,3.5,, +function,PyModule_Add,3.13,, function,PyModule_AddFunctions,3.7,, function,PyModule_AddIntConstant,3.2,, function,PyModule_AddObject,3.2,, diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 161d5fb1c59a30..0181e16f7d9b9d 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -774,6 +774,11 @@ New Features If the assertion fails, make sure that the size is set before. (Contributed by Victor Stinner in :gh:`106168`.) +* Add :c:func:`PyModule_Add` function: similar to + :c:func:`PyModule_AddObjectRef` and :c:func:`PyModule_AddObject` but + always steals a reference to the value. + (Contributed by Serhiy Storchaka in :gh:`86493`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/modsupport.h b/Include/modsupport.h index 7d4cfe853aaa7e..51061c5bc8090a 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -23,12 +23,18 @@ PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); // Add an attribute with name 'name' and value 'obj' to the module 'mod. -// On success, return 0 on success. +// On success, return 0. // On error, raise an exception and return -1. PyAPI_FUNC(int) PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value); -// Similar to PyModule_AddObjectRef() but steal a reference to 'obj' -// (Py_DECREF(obj)) on success (if it returns 0). +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 +// Similar to PyModule_AddObjectRef() but steal a reference to 'value'. +PyAPI_FUNC(int) PyModule_Add(PyObject *mod, const char *name, PyObject *value); +#endif /* Py_LIMITED_API */ + +// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal +// a reference to 'value' on success and only on success. +// Errorprone. Should not be used in new code. PyAPI_FUNC(int) PyModule_AddObject(PyObject *mod, const char *, PyObject *value); PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index e92e986b293377..4e74bb374c93bf 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -425,6 +425,7 @@ def test_windows_feature_macros(self): "PyMethodDescr_Type", "PyModuleDef_Init", "PyModuleDef_Type", + "PyModule_Add", "PyModule_AddFunctions", "PyModule_AddIntConstant", "PyModule_AddObject", diff --git a/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst b/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst new file mode 100644 index 00000000000000..3d935aceb57a79 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst @@ -0,0 +1 @@ +Add :func:`PyModule_Add` function: similar to :c:func:`PyModule_AddObjectRef` and :c:func:`PyModule_AddObject`, but always steals a reference to the value. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 8ea8fde68b833a..dd2c9910b83ccb 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2444,3 +2444,5 @@ added = '3.13' [function.PyMapping_GetOptionalItemString] added = '3.13' +[function.PyModule_Add] + added = '3.13' diff --git a/PC/python3dll.c b/PC/python3dll.c index 8f2df6950cfc05..0b54c5a707231c 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -374,6 +374,7 @@ EXPORT_FUNC(PyMemoryView_FromBuffer) EXPORT_FUNC(PyMemoryView_FromMemory) EXPORT_FUNC(PyMemoryView_FromObject) EXPORT_FUNC(PyMemoryView_GetContiguous) +EXPORT_FUNC(PyModule_Add) EXPORT_FUNC(PyModule_AddFunctions) EXPORT_FUNC(PyModule_AddIntConstant) EXPORT_FUNC(PyModule_AddObject) diff --git a/Python/modsupport.c b/Python/modsupport.c index 3db95f1f07284b..18b3322ae81d11 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -606,13 +606,16 @@ PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value) PyModule_GetName(mod)); return -1; } - - if (PyDict_SetItemString(dict, name, value)) { - return -1; - } - return 0; + return PyDict_SetItemString(dict, name, value); } +int +PyModule_Add(PyObject *mod, const char *name, PyObject *value) +{ + int res = PyModule_AddObjectRef(mod, name, value); + Py_XDECREF(value); + return res; +} int PyModule_AddObject(PyObject *mod, const char *name, PyObject *value) @@ -627,25 +630,13 @@ PyModule_AddObject(PyObject *mod, const char *name, PyObject *value) int PyModule_AddIntConstant(PyObject *m, const char *name, long value) { - PyObject *obj = PyLong_FromLong(value); - if (!obj) { - return -1; - } - int res = PyModule_AddObjectRef(m, name, obj); - Py_DECREF(obj); - return res; + return PyModule_Add(m, name, PyLong_FromLong(value)); } int PyModule_AddStringConstant(PyObject *m, const char *name, const char *value) { - PyObject *obj = PyUnicode_FromString(value); - if (!obj) { - return -1; - } - int res = PyModule_AddObjectRef(m, name, obj); - Py_DECREF(obj); - return res; + return PyModule_Add(m, name, PyUnicode_FromString(value)); } int From 3e65baee72131b49f4ce8ca2da568a6f2001ce93 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 10:50:47 +0300 Subject: [PATCH 435/446] gh-86493: Fix possible leaks in some modules initialization (GH-106768) Fix _ssl, _stat, _testinternalcapi, _threadmodule, cmath, math, posix, time. --- Modules/_ssl.c | 8 ++++---- Modules/_stat.c | 18 +++++++++--------- Modules/_testinternalcapi.c | 8 ++++---- Modules/_threadmodule.c | 4 ++-- Modules/cmathmodule.c | 15 +++++++-------- Modules/mathmodule.c | 10 +++++----- Modules/posixmodule.c | 12 ++++-------- Modules/timemodule.c | 7 ++----- 8 files changed, 37 insertions(+), 45 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 8612b3dd53924c..7c8f4225d178aa 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6118,22 +6118,22 @@ sslmodule_init_versioninfo(PyObject *m) */ libver = OpenSSL_version_num(); r = PyLong_FromUnsignedLong(libver); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_NUMBER", r)) + if (PyModule_Add(m, "OPENSSL_VERSION_NUMBER", r) < 0) return -1; parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) + if (PyModule_Add(m, "OPENSSL_VERSION_INFO", r) < 0) return -1; r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); - if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) + if (PyModule_Add(m, "OPENSSL_VERSION", r) < 0) return -1; libver = OPENSSL_VERSION_NUMBER; parse_openssl_version(libver, &major, &minor, &fix, &patch, &status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status); - if (r == NULL || PyModule_AddObject(m, "_OPENSSL_API_VERSION", r)) + if (PyModule_Add(m, "_OPENSSL_API_VERSION", r) < 0) return -1; return 0; diff --git a/Modules/_stat.c b/Modules/_stat.c index 9747d848cbacb8..6cea26175dee5e 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -591,17 +591,17 @@ stat_exec(PyObject *module) ADD_INT_MACRO(module, FILE_ATTRIBUTE_TEMPORARY); ADD_INT_MACRO(module, FILE_ATTRIBUTE_VIRTUAL); - if (PyModule_AddObject(module, "IO_REPARSE_TAG_SYMLINK", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) { - return -1; + if (PyModule_Add(module, "IO_REPARSE_TAG_SYMLINK", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_SYMLINK)) < 0) { + return -1; } - if (PyModule_AddObject(module, "IO_REPARSE_TAG_MOUNT_POINT", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) { - return -1; + if (PyModule_Add(module, "IO_REPARSE_TAG_MOUNT_POINT", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_MOUNT_POINT)) < 0) { + return -1; } - if (PyModule_AddObject(module, "IO_REPARSE_TAG_APPEXECLINK", - PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK)) < 0) { - return -1; + if (PyModule_Add(module, "IO_REPARSE_TAG_APPEXECLINK", + PyLong_FromUnsignedLong(IO_REPARSE_TAG_APPEXECLINK)) < 0) { + return -1; } #endif diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 271ad6cfcaee32..74c932fa921cd0 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1511,13 +1511,13 @@ static PyMethodDef module_functions[] = { static int module_exec(PyObject *module) { - if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD", - PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { + if (PyModule_Add(module, "SIZEOF_PYGC_HEAD", + PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) { return 1; } - if (PyModule_AddObject(module, "SIZEOF_TIME_T", - PyLong_FromSsize_t(sizeof(time_t))) < 0) { + if (PyModule_Add(module, "SIZEOF_TIME_T", + PyLong_FromSsize_t(sizeof(time_t))) < 0) { return 1; } diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 82393309b67039..d8a797f34dbc4b 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1671,8 +1671,8 @@ thread_module_exec(PyObject *module) // Round towards minus infinity timeout_max = floor(timeout_max); - if (PyModule_AddObject(module, "TIMEOUT_MAX", - PyFloat_FromDouble(timeout_max)) < 0) { + if (PyModule_Add(module, "TIMEOUT_MAX", + PyFloat_FromDouble(timeout_max)) < 0) { return -1; } diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index db8b321e72e8ce..57bc55632be485 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1217,30 +1217,29 @@ static PyMethodDef cmath_methods[] = { static int cmath_exec(PyObject *mod) { - if (PyModule_AddObject(mod, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { + if (PyModule_Add(mod, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { return -1; } - if (PyModule_AddObject(mod, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { + if (PyModule_Add(mod, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { return -1; } // 2pi - if (PyModule_AddObject(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { + if (PyModule_Add(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (PyModule_Add(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } Py_complex infj = {0.0, Py_INFINITY}; - if (PyModule_AddObject(mod, "infj", - PyComplex_FromCComplex(infj)) < 0) { + if (PyModule_Add(mod, "infj", PyComplex_FromCComplex(infj)) < 0) { return -1; } - if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { + if (PyModule_Add(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } Py_complex nanj = {0.0, fabs(Py_NAN)}; - if (PyModule_AddObject(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) { + if (PyModule_Add(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) { return -1; } diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index f5679fe3a6f362..0d238c086ac78f 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -4037,20 +4037,20 @@ math_exec(PyObject *module) if (state->str___trunc__ == NULL) { return -1; } - if (PyModule_AddObject(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { + if (PyModule_Add(module, "pi", PyFloat_FromDouble(Py_MATH_PI)) < 0) { return -1; } - if (PyModule_AddObject(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { + if (PyModule_Add(module, "e", PyFloat_FromDouble(Py_MATH_E)) < 0) { return -1; } // 2pi - if (PyModule_AddObject(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { + if (PyModule_Add(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) { return -1; } - if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { + if (PyModule_Add(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) { return -1; } - if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { + if (PyModule_Add(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) { return -1; } return 0; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index fd5e491f4611ee..23bf978d0cdbf1 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13466,7 +13466,7 @@ setup_confname_table(struct constdef *table, size_t tablesize, } Py_DECREF(o); } - return PyModule_AddObject(module, tablename, d); + return PyModule_Add(module, tablename, d); } /* Return -1 on failure, 0 on success. */ @@ -16781,11 +16781,9 @@ posixmodule_exec(PyObject *m) #endif /* Initialize environ dictionary */ - PyObject *v = convertenviron(); - Py_XINCREF(v); - if (v == NULL || PyModule_AddObject(m, "environ", v) != 0) + if (PyModule_Add(m, "environ", convertenviron()) != 0) { return -1; - Py_DECREF(v); + } if (all_ins(m)) return -1; @@ -16900,9 +16898,7 @@ posixmodule_exec(PyObject *m) Py_DECREF(unicode); } - PyModule_AddObject(m, "_have_functions", list); - - return 0; + return PyModule_Add(m, "_have_functions", list); } diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 3607855dbd8f27..912710219bd014 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -1790,11 +1790,9 @@ init_timezone(PyObject *m) return -1; } #endif // MS_WINDOWS - PyObject *tzname_obj = Py_BuildValue("(NN)", otz0, otz1); - if (tzname_obj == NULL) { + if (PyModule_Add(m, "tzname", Py_BuildValue("(NN)", otz0, otz1)) < 0) { return -1; } - PyModule_AddObject(m, "tzname", tzname_obj); #else // !HAVE_DECL_TZNAME static const time_t YEAR = (365 * 24 + 6) * 3600; time_t t; @@ -1837,10 +1835,9 @@ init_timezone(PyObject *m) PyModule_AddIntConstant(m, "daylight", janzone != julyzone); tzname_obj = Py_BuildValue("(zz)", janname, julyname); } - if (tzname_obj == NULL) { + if (PyModule_Add(m, "tzname", tzname_obj) < 0) { return -1; } - PyModule_AddObject(m, "tzname", tzname_obj); #endif // !HAVE_DECL_TZNAME if (PyErr_Occurred()) { From 4cb0b9c0a9f6a4154238c98013d2679229b1f794 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 18 Jul 2023 10:50:17 +0200 Subject: [PATCH 436/446] Docs: Normalise Argument Clinic advanced topics headings (#106842) Co-authored-by: Ezio Melotti --- Doc/howto/clinic.rst | 95 +++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 0f99cb64994ab2..12d7a77d43209a 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -560,15 +560,12 @@ Let's dive in! Congratulations, you've ported your first function to work with Argument Clinic! -Advanced topics -=============== +How-to guides +============= -Now that you've had some experience working with Argument Clinic, it's time -for some advanced topics. - -Symbolic default values ------------------------ +How to use symbolic default values +---------------------------------- The default value you provide for a parameter can't be any arbitrary expression. Currently the following are explicitly supported: @@ -583,8 +580,8 @@ expression. Currently the following are explicitly supported: to allow full expressions like ``CONSTANT - 1``.) -Renaming the C functions and variables generated by Argument Clinic -------------------------------------------------------------------- +How to to rename C functions and variables generated by Argument Clinic +----------------------------------------------------------------------- Argument Clinic automatically names the functions it generates for you. Occasionally this may cause a problem, if the generated name collides with @@ -626,8 +623,8 @@ array) would be ``file``, but the C variable would be named ``file_obj``. You can use this to rename the ``self`` parameter too! -Converting functions using PyArg_UnpackTuple --------------------------------------------- +How to convert functions using ``PyArg_UnpackTuple`` +---------------------------------------------------- To convert a function parsing its arguments with :c:func:`PyArg_UnpackTuple`, simply write out all the arguments, specifying each as an ``object``. You @@ -639,8 +636,8 @@ Currently the generated code will use :c:func:`PyArg_ParseTuple`, but this will change soon. -Optional groups ---------------- +How to use optional groups +-------------------------- Some legacy functions have a tricky approach to parsing their arguments: they count the number of positional arguments, then use a ``switch`` statement @@ -732,8 +729,8 @@ Notes: use optional groups for new code. -Using real Argument Clinic converters, instead of "legacy converters" ---------------------------------------------------------------------- +How to use real Argument Clinic converters, instead of "legacy converters" +-------------------------------------------------------------------------- To save time, and to minimize how much you need to learn to achieve your first port to Argument Clinic, the walkthrough above tells @@ -903,8 +900,8 @@ it accepts, along with the default value for each parameter. Just run ``Tools/clinic/clinic.py --converters`` to see the full list. -Py_buffer ---------- +How to use the ``Py_buffer`` converter +-------------------------------------- When using the ``Py_buffer`` converter (or the ``'s*'``, ``'w*'``, ``'*y'``, or ``'z*'`` legacy converters), @@ -912,8 +909,8 @@ you *must* not call :c:func:`PyBuffer_Release` on the provided buffer. Argument Clinic generates code that does it for you (in the parsing function). -Advanced converters -------------------- +How to use advanced converters +------------------------------ Remember those format units you skipped for your first time because they were advanced? Here's how to handle those too. @@ -944,8 +941,8 @@ hard-coded encoding strings for parameters whose format units start with ``e``. .. _default_values: -Parameter default values ------------------------- +How to assign default values to parameter +----------------------------------------- Default values for parameters can be any of a number of values. At their simplest, they can be string, int, or float literals: @@ -968,8 +965,8 @@ There's also special support for a default value of ``NULL``, and for simple expressions, documented in the following sections. -The ``NULL`` default value --------------------------- +How to use the ``NULL`` default value +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For string and object parameters, you can set them to ``None`` to indicate that there's no default. However, that means the C variable will be @@ -979,8 +976,8 @@ behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. -Expressions specified as default values ---------------------------------------- +How to use expressions as default values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The default value for a parameter can be more than just a literal value. It can be an entire expression, using math operators and looking up attributes @@ -1036,8 +1033,8 @@ you're not permitted to use: * Tuple/list/set/dict literals. -Using a return converter ------------------------- +How to use return converters +---------------------------- By default, the impl function Argument Clinic generates for you returns :c:type:`PyObject * `. @@ -1106,8 +1103,8 @@ their parameters (if any), just run ``Tools/clinic/clinic.py --converters`` for the full list. -Cloning existing functions --------------------------- +How to clone existing functions +------------------------------- If you have a number of functions that look similar, you may be able to use Clinic's "clone" feature. When you clone an existing function, @@ -1150,8 +1147,8 @@ Also, the function you are cloning from must have been previously defined in the current file. -Calling Python code -------------------- +How to call Python code +----------------------- The rest of the advanced topics require you to write Python code which lives inside your C file and modifies Argument Clinic's @@ -1178,8 +1175,8 @@ variable to the C code:: /*[python checksum:...]*/ -Using a "self converter" ------------------------- +How to use the "self converter" +------------------------------- Argument Clinic automatically adds a "self" parameter for you using a default converter. It automatically sets the ``type`` @@ -1230,8 +1227,8 @@ type for ``self``, it's best to create your own converter, subclassing [clinic start generated code]*/ -Using a "defining class" converter ----------------------------------- +How to use the "defining class" converter +----------------------------------------- Argument Clinic facilitates gaining access to the defining class of a method. This is useful for :ref:`heap type ` methods that need to fetch @@ -1293,8 +1290,8 @@ state. Example from the ``setattro`` slot method in See also :pep:`573`. -Writing a custom converter --------------------------- +How to write a custom converter +------------------------------- As we hinted at in the previous section... you can write your own converters! A converter is simply a Python class that inherits from ``CConverter``. @@ -1385,8 +1382,8 @@ You can see more examples of custom converters in the CPython source tree; grep the C files for the string ``CConverter``. -Writing a custom return converter ---------------------------------- +How to write a custom return converter +-------------------------------------- Writing a custom return converter is much like writing a custom converter. Except it's somewhat simpler, because return @@ -1400,8 +1397,8 @@ specifically the implementation of ``CReturnConverter`` and all its subclasses. -METH_O and METH_NOARGS ----------------------- +How to convert ``METH_O`` and ``METH_NOARGS`` functions +------------------------------------------------------- To convert a function using ``METH_O``, make sure the function's single argument is using the ``object`` converter, and mark the @@ -1422,8 +1419,8 @@ You can still use a self converter, a return converter, and specify a ``type`` argument to the object converter for ``METH_O``. -tp_new and tp_init functions ----------------------------- +How to convert ``tp_new`` and ``tp_init`` functions +--------------------------------------------------- You can convert ``tp_new`` and ``tp_init`` functions. Just name them ``__new__`` or ``__init__`` as appropriate. Notes: @@ -1445,8 +1442,8 @@ them ``__new__`` or ``__init__`` as appropriate. Notes: generated will throw an exception if it receives any.) -Changing and redirecting Clinic's output ----------------------------------------- +How to change and redirect Clinic's output +------------------------------------------ It can be inconvenient to have Clinic's output interspersed with your conventional hand-edited C code. Luckily, Clinic is configurable: @@ -1728,8 +1725,8 @@ it in a Clinic block lets Clinic use its existing checksum functionality to ensu the file was not modified by hand before it gets overwritten. -The #ifdef trick ----------------- +How to use the ``#ifdef`` trick +------------------------------- If you're converting a function that isn't available on all platforms, there's a trick you can use to make life a little easier. The existing @@ -1809,8 +1806,8 @@ Argument Clinic added to your file (it'll be at the very bottom), then move it above the ``PyMethodDef`` structure where that macro is used. -Using Argument Clinic in Python files -------------------------------------- +How to use Argument Clinic in Python files +------------------------------------------ It's actually possible to use Argument Clinic to preprocess Python files. There's no point to using Argument Clinic blocks, of course, as the output From aecf6aca515a203a823a87c711f15cbb82097c8b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 18 Jul 2023 00:16:32 -1000 Subject: [PATCH 437/446] gh-106751: selectors: optimize EpollSelector.select() (#106754) Co-authored-by: Pieter Eendebak --- Lib/selectors.py | 17 +++++++++-------- ...23-07-14-20-31-09.gh-issue-106751.52F6yQ.rst | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index 6d82935445d4b1..a42d1563406417 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -430,6 +430,9 @@ class PollSelector(_PollLikeSelector): if hasattr(select, 'epoll'): + _NOT_EPOLLIN = ~select.EPOLLIN + _NOT_EPOLLOUT = ~select.EPOLLOUT + class EpollSelector(_PollLikeSelector): """Epoll-based selector.""" _selector_cls = select.epoll @@ -452,22 +455,20 @@ def select(self, timeout=None): # epoll_wait() expects `maxevents` to be greater than zero; # we want to make sure that `select()` can be called when no # FD is registered. - max_ev = max(len(self._fd_to_key), 1) + max_ev = len(self._fd_to_key) or 1 ready = [] try: fd_event_list = self._selector.poll(timeout, max_ev) except InterruptedError: return ready - for fd, event in fd_event_list: - events = 0 - if event & ~select.EPOLLIN: - events |= EVENT_WRITE - if event & ~select.EPOLLOUT: - events |= EVENT_READ - key = self._fd_to_key.get(fd) + fd_to_key = self._fd_to_key + for fd, event in fd_event_list: + key = fd_to_key.get(fd) if key: + events = ((event & _NOT_EPOLLIN and EVENT_WRITE) + | (event & _NOT_EPOLLOUT and EVENT_READ)) ready.append((key, events & key.events)) return ready diff --git a/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst new file mode 100644 index 00000000000000..486b1f9bbd0a97 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-14-20-31-09.gh-issue-106751.52F6yQ.rst @@ -0,0 +1 @@ +:mod:`selectors`: Optimize ``EpollSelector.select()`` code by moving some code outside of the loop. From 3535ef1eec2563bbd7bff7c830465441fbbf759e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 18 Jul 2023 17:13:51 +0200 Subject: [PATCH 438/446] gh-106535: Document soft deprecations in What's New In Python 3.13 (#106859) --- Doc/whatsnew/3.13.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 0181e16f7d9b9d..479d08b24b112a 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -184,6 +184,13 @@ Deprecated Replace ``ctypes.ARRAY(item_type, size)`` with ``item_type * size``. (Contributed by Victor Stinner in :gh:`105733`.) +* The :mod:`getopt` and :mod:`optparse` modules are now + :term:`soft deprecated`: the :mod:`argparse` should be used for new projects. + Previously, the :mod:`optparse` module was already deprecated, its removal + was not scheduled, and no warnings was emitted: so there is no change in + practice. + (Contributed by Victor Stinner in :gh:`106535`.) + Pending Removal in Python 3.14 ------------------------------ @@ -946,6 +953,11 @@ Removed :c:func:`PyInterpreterState_Get()` on Python 3.8 and older. (Contributed by Victor Stinner in :gh:`106320`.) +* The :c:func:`PyModule_AddObject` function is now :term:`soft deprecated`: + :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef` functions should + be used instead. + (Contributed by Serhiy Storchaka in :gh:`86493`.) + Pending Removal in Python 3.14 ------------------------------ From 40f3f11a773b854c6d94746aa3b1881c8ac71b0f Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 18 Jul 2023 19:42:44 +0100 Subject: [PATCH 439/446] gh-105481: Generate the opcode lists in dis from data extracted from bytecodes.c (#106758) --- .gitattributes | 1 - Doc/library/dis.rst | 28 ++- Include/cpython/compile.h | 4 + Include/internal/pycore_opcode_metadata.h | 36 ++-- Lib/opcode.py | 129 +++++------- Lib/test/test__opcode.py | 63 ++---- ...-07-17-16-46-00.gh-issue-105481.fek_Nn.rst | 1 + Modules/_opcode.c | 60 ++++++ Modules/clinic/_opcode.c.h | 196 +++++++++++++++++- Python/bytecodes.c | 2 +- Python/ceval_macros.h | 1 + Python/compile.c | 18 ++ Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- Tools/build/generate_opcode_h.py | 6 - Tools/cases_generator/generate_cases.py | 13 +- 16 files changed, 403 insertions(+), 159 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-17-16-46-00.gh-issue-105481.fek_Nn.rst diff --git a/.gitattributes b/.gitattributes index 2616da74b48c0f..5d5558da711b17 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,7 +87,6 @@ Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/executor_cases.c.h generated Python/generated_cases.c.h generated -Include/internal/pycore_opcode_metadata.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 099b6410f165ed..6beaad3825aba8 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1803,15 +1803,12 @@ instructions: Sequence of bytecodes that access an attribute by name. -.. data:: hasjrel - - Sequence of bytecodes that have a relative jump target. +.. data:: hasjump + Sequence of bytecodes that have a jump target. All jumps + are relative. -.. data:: hasjabs - - Sequence of bytecodes that have an absolute jump target. - + .. versionadded:: 3.13 .. data:: haslocal @@ -1827,3 +1824,20 @@ instructions: Sequence of bytecodes that set an exception handler. .. versionadded:: 3.12 + + +.. data:: hasjrel + + Sequence of bytecodes that have a relative jump target. + + .. deprecated:: 3.13 + All jumps are now relative. Use :data:`hasjump`. + + +.. data:: hasjabs + + Sequence of bytecodes that have an absolute jump target. + + .. deprecated:: 3.13 + All jumps are now relative. This list is empty. + diff --git a/Include/cpython/compile.h b/Include/cpython/compile.h index cd7fd7bd377663..fd52697840203a 100644 --- a/Include/cpython/compile.h +++ b/Include/cpython/compile.h @@ -73,3 +73,7 @@ PyAPI_FUNC(int) PyUnstable_OpcodeHasArg(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasConst(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasName(int opcode); PyAPI_FUNC(int) PyUnstable_OpcodeHasJump(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasFree(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasLocal(int opcode); +PyAPI_FUNC(int) PyUnstable_OpcodeHasExc(int opcode); + diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index a5844b3135d398..d525913f8a7aba 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -955,10 +955,14 @@ enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT #define HAS_CONST_FLAG (2) #define HAS_NAME_FLAG (4) #define HAS_JUMP_FLAG (8) +#define HAS_FREE_FLAG (16) +#define HAS_LOCAL_FLAG (32) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) #define OPCODE_HAS_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_JUMP_FLAG)) +#define OPCODE_HAS_FREE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_FREE_FLAG)) +#define OPCODE_HAS_LOCAL(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_LOCAL_FLAG)) struct opcode_metadata { bool valid_entry; @@ -995,16 +999,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [NOP] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [LOAD_CLOSURE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [LOAD_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, - [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [STORE_FAST_MAYBE_NULL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, [POP_TOP] = { true, INSTR_FMT_IX, 0 }, [PUSH_NULL] = { true, INSTR_FMT_IX, 0 }, [END_FOR] = { true, INSTR_FMT_IB, 0 }, @@ -1028,7 +1032,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC, 0 }, [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC, 0 }, [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC, 0 }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB, 0 }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB, HAS_LOCAL_FLAG }, [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, 0 }, [BINARY_SLICE] = { true, INSTR_FMT_IX, 0 }, [STORE_SLICE] = { true, INSTR_FMT_IX, 0 }, @@ -1080,12 +1084,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = { [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG }, [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG }, - [DELETE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, + [DELETE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG }, + [MAKE_CELL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG }, + [DELETE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG }, + [LOAD_FROM_DICT_OR_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG }, + [LOAD_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG }, + [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG }, [COPY_FREE_VARS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, diff --git a/Lib/opcode.py b/Lib/opcode.py index 1b36300785aaea..08dfd2674dca78 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -4,10 +4,12 @@ operate on bytecodes (e.g. peephole optimizers). """ -__all__ = ["cmp_op", "hasarg", "hasconst", "hasname", "hasjrel", "hasjabs", - "haslocal", "hascompare", "hasfree", "hasexc", "opname", "opmap", - "stack_effect", "HAVE_ARGUMENT", "EXTENDED_ARG"] +# Note that __all__ is further extended below +__all__ = ["cmp_op", "opname", "opmap", "stack_effect", "hascompare", + "HAVE_ARGUMENT", "EXTENDED_ARG"] + +import _opcode from _opcode import stack_effect import sys @@ -17,55 +19,24 @@ cmp_op = ('<', '<=', '==', '!=', '>', '>=') -hasarg = [] -hasconst = [] -hasname = [] -hasjrel = [] -hasjabs = [] -haslocal = [] -hascompare = [] -hasfree = [] -hasexc = [] - ENABLE_SPECIALIZATION = True def is_pseudo(op): return op >= MIN_PSEUDO_OPCODE and op <= MAX_PSEUDO_OPCODE -oplists = [hasarg, hasconst, hasname, hasjrel, hasjabs, - haslocal, hascompare, hasfree, hasexc] - opmap = {} -## pseudo opcodes (used in the compiler) mapped to the values -## they can become in the actual code. +# pseudo opcodes (used in the compiler) mapped to the values +# they can become in the actual code. _pseudo_ops = {} def def_op(name, op): opmap[name] = op -def name_op(name, op): - def_op(name, op) - hasname.append(op) - -def jrel_op(name, op): - def_op(name, op) - hasjrel.append(op) - -def jabs_op(name, op): - def_op(name, op) - hasjabs.append(op) - def pseudo_op(name, op, real_ops): def_op(name, op) _pseudo_ops[name] = real_ops - # add the pseudo opcode to the lists its targets are in - for oplist in oplists: - res = [opmap[rop] in oplist for rop in real_ops] - if any(res): - assert all(res) - oplist.append(op) # Instruction opcodes for compiled code @@ -137,74 +108,61 @@ def pseudo_op(name, op, real_ops): HAVE_ARGUMENT = 90 # real opcodes from here have an argument: -name_op('STORE_NAME', 90) # Index in name list -name_op('DELETE_NAME', 91) # "" +def_op('STORE_NAME', 90) # Index in name list +def_op('DELETE_NAME', 91) # "" def_op('UNPACK_SEQUENCE', 92) # Number of tuple items -jrel_op('FOR_ITER', 93) +def_op('FOR_ITER', 93) def_op('UNPACK_EX', 94) -name_op('STORE_ATTR', 95) # Index in name list -name_op('DELETE_ATTR', 96) # "" -name_op('STORE_GLOBAL', 97) # "" -name_op('DELETE_GLOBAL', 98) # "" +def_op('STORE_ATTR', 95) # Index in name list +def_op('DELETE_ATTR', 96) # "" +def_op('STORE_GLOBAL', 97) # "" +def_op('DELETE_GLOBAL', 98) # "" def_op('SWAP', 99) def_op('LOAD_CONST', 100) # Index in const list -hasconst.append(100) -name_op('LOAD_NAME', 101) # Index in name list +def_op('LOAD_NAME', 101) # Index in name list def_op('BUILD_TUPLE', 102) # Number of tuple items def_op('BUILD_LIST', 103) # Number of list items def_op('BUILD_SET', 104) # Number of set items def_op('BUILD_MAP', 105) # Number of dict entries -name_op('LOAD_ATTR', 106) # Index in name list +def_op('LOAD_ATTR', 106) # Index in name list def_op('COMPARE_OP', 107) # Comparison operator -hascompare.append(107) -name_op('IMPORT_NAME', 108) # Index in name list -name_op('IMPORT_FROM', 109) # Index in name list -jrel_op('JUMP_FORWARD', 110) # Number of words to skip - -jrel_op('POP_JUMP_IF_FALSE', 114) -jrel_op('POP_JUMP_IF_TRUE', 115) -name_op('LOAD_GLOBAL', 116) # Index in name list +def_op('IMPORT_NAME', 108) # Index in name list +def_op('IMPORT_FROM', 109) # Index in name list +def_op('JUMP_FORWARD', 110) # Number of words to skip + +def_op('POP_JUMP_IF_FALSE', 114) +def_op('POP_JUMP_IF_TRUE', 115) +def_op('LOAD_GLOBAL', 116) # Index in name list def_op('IS_OP', 117) def_op('CONTAINS_OP', 118) def_op('RERAISE', 119) def_op('COPY', 120) def_op('RETURN_CONST', 121) -hasconst.append(121) def_op('BINARY_OP', 122) -jrel_op('SEND', 123) # Number of words to skip +def_op('SEND', 123) # Number of words to skip def_op('LOAD_FAST', 124) # Local variable number, no null check -haslocal.append(124) def_op('STORE_FAST', 125) # Local variable number -haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number -haslocal.append(126) def_op('LOAD_FAST_CHECK', 127) # Local variable number -haslocal.append(127) -jrel_op('POP_JUMP_IF_NOT_NONE', 128) -jrel_op('POP_JUMP_IF_NONE', 129) +def_op('POP_JUMP_IF_NOT_NONE', 128) +def_op('POP_JUMP_IF_NONE', 129) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('GET_AWAITABLE', 131) def_op('BUILD_SLICE', 133) # Number of items -jrel_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards) +def_op('JUMP_BACKWARD_NO_INTERRUPT', 134) # Number of words to skip (backwards) def_op('MAKE_CELL', 135) -hasfree.append(135) def_op('LOAD_DEREF', 137) -hasfree.append(137) def_op('STORE_DEREF', 138) -hasfree.append(138) def_op('DELETE_DEREF', 139) -hasfree.append(139) -jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) -name_op('LOAD_SUPER_ATTR', 141) +def_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) +def_op('LOAD_SUPER_ATTR', 141) def_op('CALL_FUNCTION_EX', 142) # Flags def_op('LOAD_FAST_AND_CLEAR', 143) # Local variable number -haslocal.append(143) def_op('EXTENDED_ARG', 144) -EXTENDED_ARG = 144 +EXTENDED_ARG = opmap['EXTENDED_ARG'] def_op('LIST_APPEND', 145) def_op('SET_ADD', 146) def_op('MAP_ADD', 147) -hasfree.append(148) def_op('COPY_FREE_VARS', 149) def_op('YIELD_VALUE', 150) def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py @@ -224,12 +182,10 @@ def pseudo_op(name, op, real_ops): def_op('STORE_FAST_STORE_FAST', 170) def_op('CALL', 171) def_op('KW_NAMES', 172) -hasconst.append(172) def_op('CALL_INTRINSIC_1', 173) def_op('CALL_INTRINSIC_2', 174) -name_op('LOAD_FROM_DICT_OR_GLOBALS', 175) +def_op('LOAD_FROM_DICT_OR_GLOBALS', 175) def_op('LOAD_FROM_DICT_OR_DEREF', 176) -hasfree.append(176) def_op('SET_FUNCTION_ATTRIBUTE', 177) # Attribute # Optimizer hook @@ -258,16 +214,12 @@ def pseudo_op(name, op, real_ops): def_op('INSTRUMENTED_LINE', 254) # 255 is reserved -hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT]) MIN_PSEUDO_OPCODE = 256 pseudo_op('SETUP_FINALLY', 256, ['NOP']) -hasexc.append(256) pseudo_op('SETUP_CLEANUP', 257, ['NOP']) -hasexc.append(257) pseudo_op('SETUP_WITH', 258, ['NOP']) -hasexc.append(258) pseudo_op('POP_BLOCK', 259, ['NOP']) pseudo_op('JUMP', 260, ['JUMP_FORWARD', 'JUMP_BACKWARD']) @@ -283,12 +235,29 @@ def pseudo_op(name, op, real_ops): MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1 -del def_op, name_op, jrel_op, jabs_op, pseudo_op +del def_op, pseudo_op opname = ['<%r>' % (op,) for op in range(MAX_PSEUDO_OPCODE + 1)] for op, i in opmap.items(): opname[i] = op +# The build uses older versions of Python which do not have _opcode.has_* functions +if sys.version_info[:2] >= (3, 13): + # These lists are documented as part of the dis module's API + hasarg = [op for op in opmap.values() if _opcode.has_arg(op)] + hasconst = [op for op in opmap.values() if _opcode.has_const(op)] + hasname = [op for op in opmap.values() if _opcode.has_name(op)] + hasjump = [op for op in opmap.values() if _opcode.has_jump(op)] + hasjrel = hasjump # for backward compatibility + hasjabs = [] + hasfree = [op for op in opmap.values() if _opcode.has_free(op)] + haslocal = [op for op in opmap.values() if _opcode.has_local(op)] + hasexc = [op for op in opmap.values() if _opcode.has_exc(op)] + + __all__.extend(["hasarg", "hasconst", "hasname", "hasjump", "hasjrel", + "hasjabs", "hasfree", "haslocal", "hasexc"]) + +hascompare = [opmap["COMPARE_OP"]] _nb_ops = [ ("NB_ADD", "+"), diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 7d9553d9e383a3..b3a9bcbe160453 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -7,16 +7,7 @@ from _opcode import stack_effect -class OpcodeTests(unittest.TestCase): - - def check_bool_function_result(self, func, ops, expected): - for op in ops: - if isinstance(op, str): - op = dis.opmap[op] - with self.subTest(opcode=op, func=func): - self.assertIsInstance(func(op), bool) - self.assertEqual(func(op), expected) - +class OpListTests(unittest.TestCase): def test_invalid_opcodes(self): invalid = [-100, -1, 255, 512, 513, 1000] self.check_bool_function_result(_opcode.is_valid, invalid, False) @@ -24,6 +15,9 @@ def test_invalid_opcodes(self): self.check_bool_function_result(_opcode.has_const, invalid, False) self.check_bool_function_result(_opcode.has_name, invalid, False) self.check_bool_function_result(_opcode.has_jump, invalid, False) + self.check_bool_function_result(_opcode.has_free, invalid, False) + self.check_bool_function_result(_opcode.has_local, invalid, False) + self.check_bool_function_result(_opcode.has_exc, invalid, False) def test_is_valid(self): names = [ @@ -36,43 +30,24 @@ def test_is_valid(self): opcodes = [dis.opmap[opname] for opname in names] self.check_bool_function_result(_opcode.is_valid, opcodes, True) - def test_has_arg(self): - has_arg = ['SWAP', 'LOAD_FAST', 'INSTRUMENTED_POP_JUMP_IF_TRUE', 'JUMP'] - no_arg = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] - self.check_bool_function_result(_opcode.has_arg, has_arg, True) - self.check_bool_function_result(_opcode.has_arg, no_arg, False) - - def test_has_const(self): - has_const = ['LOAD_CONST', 'RETURN_CONST', 'KW_NAMES'] - no_const = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] - self.check_bool_function_result(_opcode.has_const, has_const, True) - self.check_bool_function_result(_opcode.has_const, no_const, False) - - def test_has_name(self): - has_name = ['STORE_NAME', 'DELETE_ATTR', 'STORE_GLOBAL', 'IMPORT_FROM', - 'LOAD_FROM_DICT_OR_GLOBALS'] - no_name = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] - self.check_bool_function_result(_opcode.has_name, has_name, True) - self.check_bool_function_result(_opcode.has_name, no_name, False) + def test_oplists(self): + def check_function(self, func, expected): + for op in [-10, 520]: + with self.subTest(opcode=op, func=func): + res = func(op) + self.assertIsInstance(res, bool) + self.assertEqual(res, op in expected) - def test_has_jump(self): - has_jump = ['FOR_ITER', 'JUMP_FORWARD', 'JUMP', 'POP_JUMP_IF_TRUE', 'SEND'] - no_jump = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE'] - self.check_bool_function_result(_opcode.has_jump, has_jump, True) - self.check_bool_function_result(_opcode.has_jump, no_jump, False) + check_function(self, _opcode.has_arg, dis.hasarg) + check_function(self, _opcode.has_const, dis.hasconst) + check_function(self, _opcode.has_name, dis.hasname) + check_function(self, _opcode.has_jump, dis.hasjump) + check_function(self, _opcode.has_free, dis.hasfree) + check_function(self, _opcode.has_local, dis.haslocal) + check_function(self, _opcode.has_exc, dis.hasexc) - # the following test is part of the refactor, it will be removed soon - def test_against_legacy_bool_values(self): - # limiting to ops up to ENTER_EXECUTOR, because everything after that - # is not currently categorized correctly in opcode.py. - for op in range(0, opcode.opmap['ENTER_EXECUTOR']): - with self.subTest(op=op): - if opcode.opname[op] != f'<{op}>': - self.assertEqual(op in dis.hasarg, _opcode.has_arg(op)) - self.assertEqual(op in dis.hasconst, _opcode.has_const(op)) - self.assertEqual(op in dis.hasname, _opcode.has_name(op)) - self.assertEqual(op in dis.hasjrel, _opcode.has_jump(op)) +class OpListTests(unittest.TestCase): def test_stack_effect(self): self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) diff --git a/Misc/NEWS.d/next/Library/2023-07-17-16-46-00.gh-issue-105481.fek_Nn.rst b/Misc/NEWS.d/next/Library/2023-07-17-16-46-00.gh-issue-105481.fek_Nn.rst new file mode 100644 index 00000000000000..d82eb987c83e96 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-17-16-46-00.gh-issue-105481.fek_Nn.rst @@ -0,0 +1 @@ +The various opcode lists in the :mod:`dis` module are now generated from bytecodes.c instead of explicitly constructed in opcode.py. diff --git a/Modules/_opcode.c b/Modules/_opcode.c index b3b9873d21a5be..daabdce1655777 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -147,6 +147,63 @@ _opcode_has_jump_impl(PyObject *module, int opcode) /*[clinic input] +_opcode.has_free -> bool + + opcode: int + +Return True if the opcode accesses a free variable, False otherwise. + +Note that 'free' in this context refers to names in the current scope +that are referenced by inner scopes or names in outer scopes that are +referenced from this scope. It does not include references to global +or builtin scopes. +[clinic start generated code]*/ + +static int +_opcode_has_free_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=d81ae4d79af0ee26 input=117dcd5c19c1139b]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasFree(opcode); + +} + +/*[clinic input] + +_opcode.has_local -> bool + + opcode: int + +Return True if the opcode accesses a local variable, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_local_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=da5a8616b7a5097b input=9a798ee24aaef49d]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasLocal(opcode); +} + +/*[clinic input] + +_opcode.has_exc -> bool + + opcode: int + +Return True if the opcode sets an exception handler, False otherwise. +[clinic start generated code]*/ + +static int +_opcode_has_exc_impl(PyObject *module, int opcode) +/*[clinic end generated code: output=41b68dff0ec82a52 input=db0e4bdb9bf13fa5]*/ +{ + return PyUnstable_OpcodeIsValid(opcode) && + PyUnstable_OpcodeHasExc(opcode); +} + +/*[clinic input] + _opcode.get_specialization_stats Return the specialization stats @@ -171,6 +228,9 @@ opcode_functions[] = { _OPCODE_HAS_CONST_METHODDEF _OPCODE_HAS_NAME_METHODDEF _OPCODE_HAS_JUMP_METHODDEF + _OPCODE_HAS_FREE_METHODDEF + _OPCODE_HAS_LOCAL_METHODDEF + _OPCODE_HAS_EXC_METHODDEF _OPCODE_GET_SPECIALIZATION_STATS_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/clinic/_opcode.c.h b/Modules/clinic/_opcode.c.h index 3eb050e470c343..e6381fa73a5506 100644 --- a/Modules/clinic/_opcode.c.h +++ b/Modules/clinic/_opcode.c.h @@ -401,6 +401,200 @@ _opcode_has_jump(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb return return_value; } +PyDoc_STRVAR(_opcode_has_free__doc__, +"has_free($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses a free variable, False otherwise.\n" +"\n" +"Note that \'free\' in this context refers to names in the current scope\n" +"that are referenced by inner scopes or names in outer scopes that are\n" +"referenced from this scope. It does not include references to global\n" +"or builtin scopes."); + +#define _OPCODE_HAS_FREE_METHODDEF \ + {"has_free", _PyCFunction_CAST(_opcode_has_free), METH_FASTCALL|METH_KEYWORDS, _opcode_has_free__doc__}, + +static int +_opcode_has_free_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_free(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_free", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_free_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_local__doc__, +"has_local($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode accesses a local variable, False otherwise."); + +#define _OPCODE_HAS_LOCAL_METHODDEF \ + {"has_local", _PyCFunction_CAST(_opcode_has_local), METH_FASTCALL|METH_KEYWORDS, _opcode_has_local__doc__}, + +static int +_opcode_has_local_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_local(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_local", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_local_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_opcode_has_exc__doc__, +"has_exc($module, /, opcode)\n" +"--\n" +"\n" +"Return True if the opcode sets an exception handler, False otherwise."); + +#define _OPCODE_HAS_EXC_METHODDEF \ + {"has_exc", _PyCFunction_CAST(_opcode_has_exc), METH_FASTCALL|METH_KEYWORDS, _opcode_has_exc__doc__}, + +static int +_opcode_has_exc_impl(PyObject *module, int opcode); + +static PyObject * +_opcode_has_exc(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + 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(opcode), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"opcode", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "has_exc", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int opcode; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + opcode = _PyLong_AsInt(args[0]); + if (opcode == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = _opcode_has_exc_impl(module, opcode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_opcode_get_specialization_stats__doc__, "get_specialization_stats($module, /)\n" "--\n" @@ -418,4 +612,4 @@ _opcode_get_specialization_stats(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _opcode_get_specialization_stats_impl(module); } -/*[clinic end generated code: output=ae2b2ef56d582180 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e507bf14fb2796f8 input=a9049054013a1b77]*/ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 19fb138ee64cba..ea136a3fca2e02 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3604,7 +3604,7 @@ dummy_func( _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); + _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, LOCALS_ARRAY); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_OP, deferred); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 874bd45becf0c9..c2c323317d10f9 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -234,6 +234,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* Local variable macros */ +#define LOCALS_ARRAY (frame->localsplus) #define GETLOCAL(i) (frame->localsplus[i]) /* The SETLOCAL() macro must not DECREF the local variable in-place and diff --git a/Python/compile.c b/Python/compile.c index 2a735382c0cfda..d5405b46561820 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -896,6 +896,24 @@ PyUnstable_OpcodeHasJump(int opcode) return OPCODE_HAS_JUMP(opcode); } +int +PyUnstable_OpcodeHasFree(int opcode) +{ + return OPCODE_HAS_FREE(opcode); +} + +int +PyUnstable_OpcodeHasLocal(int opcode) +{ + return OPCODE_HAS_LOCAL(opcode); +} + +int +PyUnstable_OpcodeHasExc(int opcode) +{ + return IS_BLOCK_PUSH_OPCODE(opcode); +} + static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index f492c1fa9d8e3f..e1f8b9f208c76d 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2449,7 +2449,7 @@ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); + _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, LOCALS_ARRAY); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_OP, deferred); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0a8e4da46b8be3..b2b0aa6ece4816 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4451,7 +4451,7 @@ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); + _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, LOCALS_ARRAY); DISPATCH_SAME_OPARG(); } STAT_INC(BINARY_OP, deferred); diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 2e841e6097aa25..5b0560e6b21a99 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -84,13 +84,7 @@ def main(opcode_py, opcode = get_python_module_dict(opcode_py) opmap = opcode['opmap'] opname = opcode['opname'] - hasarg = opcode['hasarg'] - hasconst = opcode['hasconst'] - hasjrel = opcode['hasjrel'] - hasjabs = opcode['hasjabs'] is_pseudo = opcode['is_pseudo'] - _pseudo_ops = opcode['_pseudo_ops'] - ENABLE_SPECIALIZATION = opcode["ENABLE_SPECIALIZATION"] MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"] diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 2713fc6774e845..33eff548a18809 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -261,6 +261,8 @@ class InstructionFlags: HAS_CONST_FLAG: bool HAS_NAME_FLAG: bool HAS_JUMP_FLAG: bool + HAS_FREE_FLAG: bool + HAS_LOCAL_FLAG: bool def __post_init__(self): self.bitmask = { @@ -269,16 +271,25 @@ def __post_init__(self): @staticmethod def fromInstruction(instr: "AnyInstruction"): + + has_free = (variable_used(instr, "PyCell_New") or + variable_used(instr, "PyCell_GET") or + variable_used(instr, "PyCell_SET")) + return InstructionFlags( HAS_ARG_FLAG=variable_used(instr, "oparg"), HAS_CONST_FLAG=variable_used(instr, "FRAME_CO_CONSTS"), HAS_NAME_FLAG=variable_used(instr, "FRAME_CO_NAMES"), HAS_JUMP_FLAG=variable_used(instr, "JUMPBY"), + HAS_FREE_FLAG=has_free, + HAS_LOCAL_FLAG=(variable_used(instr, "GETLOCAL") or + variable_used(instr, "SETLOCAL")) and + not has_free, ) @staticmethod def newEmpty(): - return InstructionFlags(False, False, False, False) + return InstructionFlags(False, False, False, False, False, False) def add(self, other: "InstructionFlags") -> None: for name, value in dataclasses.asdict(other).items(): From a293fa5915c21b21f5cb8ed9649fbdb37b4c1421 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 18 Jul 2023 23:59:53 +0300 Subject: [PATCH 440/446] gh-86493: Use PyModule_Add() instead of PyModule_AddObjectRef() (GH-106860) --- Modules/_ctypes/_ctypes.c | 8 +------- Modules/_hashopenssl.c | 14 ++------------ Modules/_json.c | 14 ++------------ Modules/_sre/sre.c | 7 +------ Modules/_ssl.c | 8 +------- Modules/_testcapi/mem.c | 8 +++----- Modules/_testcapi/watchers.c | 8 +------- Modules/_testsinglephase.c | 8 +------- Modules/pyexpat.c | 13 +++++-------- Modules/socketmodule.c | 12 ++---------- Modules/unicodedata.c | 8 +------- PC/msvcrtmodule.c | 17 +++-------------- PC/winreg.c | 10 ++-------- Python/import.c | 7 +------ 14 files changed, 26 insertions(+), 116 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 7624c15ac522da..200fd36748c403 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5740,15 +5740,9 @@ _ctypes_add_objects(PyObject *mod) { #define MOD_ADD(name, expr) \ do { \ - PyObject *obj = (expr); \ - if (obj == NULL) { \ + if (PyModule_Add(mod, name, (expr)) < 0) { \ return -1; \ } \ - if (PyModule_AddObjectRef(mod, name, obj) < 0) { \ - Py_DECREF(obj); \ - return -1; \ - } \ - Py_DECREF(obj); \ } while (0) MOD_ADD("_pointer_type_cache", Py_NewRef(_ctypes_ptrtype_cache)); diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 011cb765ed82e6..246eea74098820 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -2189,7 +2189,6 @@ hashlib_init_constructors(PyObject *module) */ PyModuleDef *mdef; PyMethodDef *fdef; - PyObject *proxy; PyObject *func, *name_obj; _hashlibstate *state = get_hashlib_state(module); @@ -2224,17 +2223,8 @@ hashlib_init_constructors(PyObject *module) } } - proxy = PyDictProxy_New(state->constructs); - if (proxy == NULL) { - return -1; - } - - int rc = PyModule_AddObjectRef(module, "_constructors", proxy); - Py_DECREF(proxy); - if (rc < 0) { - return -1; - } - return 0; + return PyModule_Add(module, "_constructors", + PyDictProxy_New(state->constructs)); } static int diff --git a/Modules/_json.c b/Modules/_json.c index 360fb453cd111c..2d0e30d70932bd 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1756,22 +1756,12 @@ static int _json_exec(PyObject *module) { PyObject *PyScannerType = PyType_FromSpec(&PyScannerType_spec); - if (PyScannerType == NULL) { - return -1; - } - int rc = PyModule_AddObjectRef(module, "make_scanner", PyScannerType); - Py_DECREF(PyScannerType); - if (rc < 0) { + if (PyModule_Add(module, "make_scanner", PyScannerType) < 0) { return -1; } PyObject *PyEncoderType = PyType_FromSpec(&PyEncoderType_spec); - if (PyEncoderType == NULL) { - return -1; - } - rc = PyModule_AddObjectRef(module, "make_encoder", PyEncoderType); - Py_DECREF(PyEncoderType); - if (rc < 0) { + if (PyModule_Add(module, "make_encoder", PyEncoderType) < 0) { return -1; } diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index f34a353432dec0..ddbdc9f478aab3 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -3195,12 +3195,7 @@ do { \ #define ADD_ULONG_CONSTANT(module, name, value) \ do { \ - PyObject *o = PyLong_FromUnsignedLong(value); \ - if (!o) \ - goto error; \ - int res = PyModule_AddObjectRef(module, name, o); \ - Py_DECREF(o); \ - if (res < 0) { \ + if (PyModule_Add(module, name, PyLong_FromUnsignedLong(value)) < 0) { \ goto error; \ } \ } while (0) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 7c8f4225d178aa..ed720b4295f8ec 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -5773,13 +5773,7 @@ static int sslmodule_add_option(PyObject *m, const char *name, uint64_t value) { Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value)); - PyObject *obj = PyLong_FromUnsignedLongLong(value); - if (obj == NULL) { - return -1; - } - int res = PyModule_AddObjectRef(m, name, obj); - Py_DECREF(obj); - return res; + return PyModule_Add(m, name, PyLong_FromUnsignedLongLong(value)); } diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index 16bda66af554af..979b3a4b2b1af6 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -692,13 +692,11 @@ _PyTestCapi_Init_Mem(PyObject *mod) PyObject *v; #ifdef WITH_PYMALLOC - v = Py_NewRef(Py_True); + v = Py_True; #else - v = Py_NewRef(Py_False); + v = Py_False; #endif - int rc = PyModule_AddObjectRef(mod, "WITH_PYMALLOC", v); - Py_DECREF(v); - if (rc < 0) { + if (PyModule_AddObjectRef(mod, "WITH_PYMALLOC", v) < 0) { return -1; } diff --git a/Modules/_testcapi/watchers.c b/Modules/_testcapi/watchers.c index 7167943fffab39..4cf567b3314980 100644 --- a/Modules/_testcapi/watchers.c +++ b/Modules/_testcapi/watchers.c @@ -516,13 +516,7 @@ static PyFunction_WatchCallback func_watcher_callbacks[NUM_TEST_FUNC_WATCHERS] = static int add_func_event(PyObject *module, const char *name, PyFunction_WatchEvent event) { - PyObject *value = PyLong_FromLong(event); - if (value == NULL) { - return -1; - } - int ok = PyModule_AddObjectRef(module, name, value); - Py_DECREF(value); - return ok; + return PyModule_Add(module, name, PyLong_FromLong(event)); } static PyObject * diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index 922b41005e8419..c42a15a0eff494 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -137,13 +137,7 @@ init_module(PyObject *module, module_state *state) } double d = _PyTime_AsSecondsDouble(state->initialized); - PyObject *initialized = PyFloat_FromDouble(d); - if (initialized == NULL) { - return -1; - } - int rc = PyModule_AddObjectRef(module, "_module_initialized", initialized); - Py_DECREF(initialized); - if (rc < 0) { + if (PyModule_Add(module, "_module_initialized", PyFloat_FromDouble(d)) < 0) { return -1; } diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index 5721ed4412be57..bd8a98a46579a3 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -1812,16 +1812,13 @@ add_errors_module(PyObject *mod) goto error; } - int rc = PyModule_AddObjectRef(errors_module, "codes", codes_dict); - Py_CLEAR(codes_dict); - if (rc < 0) { - goto error; + if (PyModule_Add(errors_module, "codes", codes_dict) < 0) { + Py_DECREF(rev_codes_dict); + return -1; } - rc = PyModule_AddObjectRef(errors_module, "messages", rev_codes_dict); - Py_CLEAR(rev_codes_dict); - if (rc < 0) { - goto error; + if (PyModule_Add(errors_module, "messages", rev_codes_dict) < 0) { + return -1; } return 0; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 1d3f34b857a1d2..39bbc911712376 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -7425,9 +7425,7 @@ socket_exec(PyObject *m) sock_free_api(capi); goto error; } - int rc = PyModule_AddObjectRef(m, PySocket_CAPI_NAME, capsule); - Py_DECREF(capsule); - if (rc < 0) { + if (PyModule_Add(m, PySocket_CAPI_NAME, capsule) < 0) { goto error; } @@ -8818,13 +8816,7 @@ socket_exec(PyObject *m) }; int i; for (i = 0; i < Py_ARRAY_LENGTH(codes); ++i) { - PyObject *tmp = PyLong_FromUnsignedLong(codes[i]); - if (tmp == NULL) { - goto error; - } - int rc = PyModule_AddObjectRef(m, names[i], tmp); - Py_DECREF(tmp); - if (rc < 0) { + if (PyModule_Add(m, names[i], PyLong_FromUnsignedLong(codes[i])) < 0) { goto error; } } diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index b6e50528a23c86..966123f4624c08 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1496,13 +1496,7 @@ unicodedata_exec(PyObject *module) } /* Export C API */ - PyObject *capsule = unicodedata_create_capi(); - if (capsule == NULL) { - return -1; - } - int rc = PyModule_AddObjectRef(module, "_ucnhash_CAPI", capsule); - Py_DECREF(capsule); - if (rc < 0) { + if (PyModule_Add(module, "_ucnhash_CAPI", unicodedata_create_capi()) < 0) { return -1; } return 0; diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 53ef26b732f615..afc810adcf7499 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -565,15 +565,9 @@ static struct PyMethodDef msvcrt_functions[] = { }; static int -insertptr(PyObject *mod, char *name, void *value) +insertptr(PyObject *mod, const char *name, void *value) { - PyObject *v = PyLong_FromVoidPtr(value); - if (v == NULL) { - return -1; - } - int rc = PyModule_AddObjectRef(mod, name, v); - Py_DECREF(v); - return rc; + return PyModule_Add(mod, name, PyLong_FromVoidPtr(value)); } #define INSERTINT(MOD, NAME, VAL) do { \ @@ -646,12 +640,7 @@ exec_module(PyObject* m) _VC_CRT_MINOR_VERSION, _VC_CRT_BUILD_VERSION, _VC_CRT_RBUILD_VERSION); - if (version == NULL) { - return -1; - } - int st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version); - Py_DECREF(version); - if (st < 0) { + if (PyModule_Add(m, "CRT_ASSEMBLY_VERSION", version) < 0) { return -1; } #endif diff --git a/PC/winreg.c b/PC/winreg.c index aa2055c7e619d2..5252f78a9bdf72 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -2079,15 +2079,9 @@ static struct PyMethodDef winreg_methods[] = { } while (0) static int -inskey(PyObject *mod, char *name, HKEY key) +inskey(PyObject *mod, const char *name, HKEY key) { - PyObject *v = PyLong_FromVoidPtr(key); - if (v == NULL) { - return -1; - } - int rc = PyModule_AddObjectRef(mod, name, v); - Py_DECREF(v); - return rc; + return PyModule_Add(mod, name, PyLong_FromVoidPtr(key)); } #define ADD_KEY(VAL) do { \ diff --git a/Python/import.c b/Python/import.c index 3e52a4e4eb1450..cf993cbd62a2ef 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3844,14 +3844,9 @@ imp_module_exec(PyObject *module) { const wchar_t *mode = _Py_GetConfig()->check_hash_pycs_mode; PyObject *pyc_mode = PyUnicode_FromWideChar(mode, -1); - if (pyc_mode == NULL) { + if (PyModule_Add(module, "check_hash_based_pycs", pyc_mode) < 0) { return -1; } - if (PyModule_AddObjectRef(module, "check_hash_based_pycs", pyc_mode) < 0) { - Py_DECREF(pyc_mode); - return -1; - } - Py_DECREF(pyc_mode); return 0; } From 505eede38d141d43e40e246319b157e3c77211d3 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 19 Jul 2023 00:46:50 +0200 Subject: [PATCH 441/446] Docs: Argument Clinic: Group guides about default values (#106872) Previous ToC layout (excerpt): - How to use symbolic default values ... - How to assign default values to parameter - How to use the ``NULL`` default value - How to use expressions as default values New layout: - How to assign default values to parameter - The ``NULL`` default value - Symbolic default values - Expressions as default values --- Doc/howto/clinic.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Doc/howto/clinic.rst b/Doc/howto/clinic.rst index 12d7a77d43209a..efeb22c618b512 100644 --- a/Doc/howto/clinic.rst +++ b/Doc/howto/clinic.rst @@ -564,22 +564,6 @@ How-to guides ============= -How to use symbolic default values ----------------------------------- - -The default value you provide for a parameter can't be any arbitrary -expression. Currently the following are explicitly supported: - -* Numeric constants (integer and float) -* String constants -* ``True``, ``False``, and ``None`` -* Simple symbolic constants like ``sys.maxsize``, which must - start with the name of the module - -(In the future, this may need to get even more elaborate, -to allow full expressions like ``CONSTANT - 1``.) - - How to to rename C functions and variables generated by Argument Clinic ----------------------------------------------------------------------- @@ -965,8 +949,8 @@ There's also special support for a default value of ``NULL``, and for simple expressions, documented in the following sections. -How to use the ``NULL`` default value -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The ``NULL`` default value +^^^^^^^^^^^^^^^^^^^^^^^^^^ For string and object parameters, you can set them to ``None`` to indicate that there's no default. However, that means the C variable will be @@ -976,8 +960,24 @@ behaves like a default value of ``None``, but the C variable is initialized with ``NULL``. -How to use expressions as default values -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Symbolic default values +^^^^^^^^^^^^^^^^^^^^^^^ + +The default value you provide for a parameter can't be any arbitrary +expression. Currently the following are explicitly supported: + +* Numeric constants (integer and float) +* String constants +* ``True``, ``False``, and ``None`` +* Simple symbolic constants like ``sys.maxsize``, which must + start with the name of the module + +(In the future, this may need to get even more elaborate, +to allow full expressions like ``CONSTANT - 1``.) + + +Expressions as default values +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The default value for a parameter can be more than just a literal value. It can be an entire expression, using math operators and looking up attributes From 663854d73b35feeb004ae0970e45b53ca27774a1 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 18 Jul 2023 15:20:31 -0800 Subject: [PATCH 442/446] gh-106727: Make `inspect.getsource` smarter for class for same name definitions (#106815) --- Lib/inspect.py | 57 +++++++++++++++---- Lib/test/inspect_fodder2.py | 20 +++++++ Lib/test/test_inspect.py | 5 +- ...-07-16-23-59-33.gh-issue-106727.bk3uCu.rst | 1 + 4 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-16-23-59-33.gh-issue-106727.bk3uCu.rst diff --git a/Lib/inspect.py b/Lib/inspect.py index 15f94a194856ac..675714dc8b3f70 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -1034,9 +1034,13 @@ class ClassFoundException(Exception): class _ClassFinder(ast.NodeVisitor): - def __init__(self, qualname): + def __init__(self, cls, tree, lines, qualname): self.stack = [] + self.cls = cls + self.tree = tree + self.lines = lines self.qualname = qualname + self.lineno_found = [] def visit_FunctionDef(self, node): self.stack.append(node.name) @@ -1057,11 +1061,48 @@ def visit_ClassDef(self, node): line_number = node.lineno # decrement by one since lines starts with indexing by zero - line_number -= 1 - raise ClassFoundException(line_number) + self.lineno_found.append((line_number - 1, node.end_lineno)) self.generic_visit(node) self.stack.pop() + def get_lineno(self): + self.visit(self.tree) + lineno_found_number = len(self.lineno_found) + if lineno_found_number == 0: + raise OSError('could not find class definition') + elif lineno_found_number == 1: + return self.lineno_found[0][0] + else: + # We have multiple candidates for the class definition. + # Now we have to guess. + + # First, let's see if there are any method definitions + for member in self.cls.__dict__.values(): + if isinstance(member, types.FunctionType): + for lineno, end_lineno in self.lineno_found: + if lineno <= member.__code__.co_firstlineno <= end_lineno: + return lineno + + class_strings = [(''.join(self.lines[lineno: end_lineno]), lineno) + for lineno, end_lineno in self.lineno_found] + + # Maybe the class has a docstring and it's unique? + if self.cls.__doc__: + ret = None + for candidate, lineno in class_strings: + if self.cls.__doc__.strip() in candidate: + if ret is None: + ret = lineno + else: + break + else: + if ret is not None: + return ret + + # We are out of ideas, just return the last one found, which is + # slightly better than previous ones + return self.lineno_found[-1][0] + def findsource(object): """Return the entire source file and starting line number for an object. @@ -1098,14 +1139,8 @@ def findsource(object): qualname = object.__qualname__ source = ''.join(lines) tree = ast.parse(source) - class_finder = _ClassFinder(qualname) - try: - class_finder.visit(tree) - except ClassFoundException as e: - line_number = e.args[0] - return lines, line_number - else: - raise OSError('could not find class definition') + class_finder = _ClassFinder(object, tree, lines, qualname) + return lines, class_finder.get_lineno() if ismethod(object): object = object.__func__ diff --git a/Lib/test/inspect_fodder2.py b/Lib/test/inspect_fodder2.py index 03464613694605..8639cf2e72cd7a 100644 --- a/Lib/test/inspect_fodder2.py +++ b/Lib/test/inspect_fodder2.py @@ -290,3 +290,23 @@ def complex_decorated(foo=0, bar=lambda: 0): nested_lambda = ( lambda right: [].map( lambda length: ())) + +# line 294 +if True: + class cls296: + def f(): + pass +else: + class cls296: + def g(): + pass + +# line 304 +if False: + class cls310: + def f(): + pass +else: + class cls310: + def g(): + pass diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 64afeec351b353..33a593f3591d68 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -949,7 +949,6 @@ def test_class_decorator(self): self.assertSourceEqual(mod2.cls196.cls200, 198, 201) def test_class_inside_conditional(self): - self.assertSourceEqual(mod2.cls238, 238, 240) self.assertSourceEqual(mod2.cls238.cls239, 239, 240) def test_multiple_children_classes(self): @@ -975,6 +974,10 @@ def test_nested_class_definition_inside_async_function(self): self.assertSourceEqual(mod2.cls226, 231, 235) self.assertSourceEqual(asyncio.run(mod2.cls226().func232()), 233, 234) + def test_class_definition_same_name_diff_methods(self): + self.assertSourceEqual(mod2.cls296, 296, 298) + self.assertSourceEqual(mod2.cls310, 310, 312) + class TestNoEOL(GetSourceBase): def setUp(self): self.tempdir = TESTFN + '_dir' diff --git a/Misc/NEWS.d/next/Library/2023-07-16-23-59-33.gh-issue-106727.bk3uCu.rst b/Misc/NEWS.d/next/Library/2023-07-16-23-59-33.gh-issue-106727.bk3uCu.rst new file mode 100644 index 00000000000000..e4ea0ce1890d2f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-16-23-59-33.gh-issue-106727.bk3uCu.rst @@ -0,0 +1 @@ +Make :func:`inspect.getsource` smarter for class for same name definitions From 7513e2e7e48f6c004ed9bce55f2dcc6b388e02cd Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 19 Jul 2023 10:18:23 +0900 Subject: [PATCH 443/446] gh-106751: Optimize KqueueSelector.select() for many iteration case (gh-106864) --- Lib/selectors.py | 14 ++++++-------- .../2023-07-18-23-05-12.gh-issue-106751.tVvzN_.rst | 2 ++ 2 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-18-23-05-12.gh-issue-106751.tVvzN_.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index a42d1563406417..d13405963f219d 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -547,23 +547,21 @@ def select(self, timeout=None): # If max_ev is 0, kqueue will ignore the timeout. For consistent # behavior with the other selector classes, we prevent that here # (using max). See https://bugs.python.org/issue29255 - max_ev = max(len(self._fd_to_key), 1) + max_ev = len(self._fd_to_key) or 1 ready = [] try: kev_list = self._selector.control(None, max_ev, timeout) except InterruptedError: return ready + + fd_to_key_get = self._fd_to_key.get for kev in kev_list: fd = kev.ident flag = kev.filter - events = 0 - if flag == select.KQ_FILTER_READ: - events |= EVENT_READ - if flag == select.KQ_FILTER_WRITE: - events |= EVENT_WRITE - - key = self._fd_to_key.get(fd) + key = fd_to_key_get(fd) if key: + events = ((flag == select.KQ_FILTER_READ and EVENT_READ) + | (flag == select.KQ_FILTER_WRITE and EVENT_WRITE)) ready.append((key, events & key.events)) return ready diff --git a/Misc/NEWS.d/next/Library/2023-07-18-23-05-12.gh-issue-106751.tVvzN_.rst b/Misc/NEWS.d/next/Library/2023-07-18-23-05-12.gh-issue-106751.tVvzN_.rst new file mode 100644 index 00000000000000..1cb8424b6221ee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-18-23-05-12.gh-issue-106751.tVvzN_.rst @@ -0,0 +1,2 @@ +Optimize :meth:`KqueueSelector.select` for many iteration case. Patch By +Dong-hee Na. From e6f96cf9c62e38514e8f5465a1c43f85d861adb2 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 19 Jul 2023 15:12:38 +0900 Subject: [PATCH 444/446] gh-106751: Optimize SelectSelector.select() for many iteration case (gh-106879) --- Lib/selectors.py | 18 ++++++++---------- ...3-07-19-10-45-24.gh-issue-106751.3HJ1of.rst | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-19-10-45-24.gh-issue-106751.3HJ1of.rst diff --git a/Lib/selectors.py b/Lib/selectors.py index d13405963f219d..13497a24097232 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -314,17 +314,15 @@ def select(self, timeout=None): r, w, _ = self._select(self._readers, self._writers, [], timeout) except InterruptedError: return ready - r = set(r) - w = set(w) - for fd in r | w: - events = 0 - if fd in r: - events |= EVENT_READ - if fd in w: - events |= EVENT_WRITE - - key = self._fd_to_key.get(fd) + r = frozenset(r) + w = frozenset(w) + rw = r | w + fd_to_key_get = self._fd_to_key.get + for fd in rw: + key = fd_to_key_get(fd) if key: + events = ((fd in r and EVENT_READ) + | (fd in w and EVENT_WRITE)) ready.append((key, events & key.events)) return ready diff --git a/Misc/NEWS.d/next/Library/2023-07-19-10-45-24.gh-issue-106751.3HJ1of.rst b/Misc/NEWS.d/next/Library/2023-07-19-10-45-24.gh-issue-106751.3HJ1of.rst new file mode 100644 index 00000000000000..2696b560371d13 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-19-10-45-24.gh-issue-106751.3HJ1of.rst @@ -0,0 +1,2 @@ +Optimize :meth:`SelectSelector.select` for many iteration case. Patch By +Dong-hee Na. From 70b961ed93f67e34d0624e178f6029c886afaeee Mon Sep 17 00:00:00 2001 From: Yonatan Bitton Date: Wed, 19 Jul 2023 14:03:47 +0300 Subject: [PATCH 445/446] gh-104090: Fix unittest collectedDurations resources leak (#106795) --- Lib/unittest/result.py | 3 ++- .../next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index 7757dba9670b43..3ace0a5b7bf2ef 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -166,7 +166,8 @@ def addDuration(self, test, elapsed): """ # support for a TextTestRunner using an old TestResult class if hasattr(self, "collectedDurations"): - self.collectedDurations.append((test, elapsed)) + # Pass test repr and not the test object itself to avoid resources leak + self.collectedDurations.append((str(test), elapsed)) def wasSuccessful(self): """Tells whether or not this result was a success.""" diff --git a/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst b/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst new file mode 100644 index 00000000000000..5cc6c5bbe15446 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-07-16-02-57-08.gh-issue-104090.cKtK7g.rst @@ -0,0 +1 @@ +Avoid creating a reference to the test object in :meth:`~unittest.TestResult.collectedDurations`. From a1a3193990cd6658c1fe859b88a2bc03971a16df Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 19 Jul 2023 13:07:40 +0200 Subject: [PATCH 446/446] Export _PyEval_SetProfile() as a function, not data (#106887) --- Include/cpython/ceval.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index a9616bd6a4f518..5255d715142b97 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -4,7 +4,7 @@ PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); PyAPI_FUNC(void) PyEval_SetProfileAllThreads(Py_tracefunc, PyObject *); -PyAPI_DATA(int) _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg); +PyAPI_FUNC(int) _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg); PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); PyAPI_FUNC(void) PyEval_SetTraceAllThreads(Py_tracefunc, PyObject *); PyAPI_FUNC(int) _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg);