diff options
author | Guido van Rossum <guido@python.org> | 2022-11-03 16:50:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-03 16:50:35 (GMT) |
commit | 916af11a976ca2faf0a8a77b0aaf71893e549cfe (patch) | |
tree | 0b737bbec1f096a000b602a285a4e61bdf41fc8a /Tools/cases_generator | |
parent | b8a9f13abb61bd91a368e2d3f339de736863050f (diff) | |
download | cpython-916af11a976ca2faf0a8a77b0aaf71893e549cfe.zip cpython-916af11a976ca2faf0a8a77b0aaf71893e549cfe.tar.gz cpython-916af11a976ca2faf0a8a77b0aaf71893e549cfe.tar.bz2 |
GH-98831: Remove redundant extract_cases.py script (GH-99065)
Debt I owe from PR GH-98830.
Diffstat (limited to 'Tools/cases_generator')
-rw-r--r-- | Tools/cases_generator/README.md | 6 | ||||
-rw-r--r-- | Tools/cases_generator/bytecodes_template.c | 85 | ||||
-rw-r--r-- | Tools/cases_generator/extract_cases.py | 247 |
3 files changed, 0 insertions, 338 deletions
diff --git a/Tools/cases_generator/README.md b/Tools/cases_generator/README.md index 2d00e30..abcafe2 100644 --- a/Tools/cases_generator/README.md +++ b/Tools/cases_generator/README.md @@ -8,12 +8,6 @@ What's currently here: - `generate_cases.py`: driver script to read `Python/bytecodes.c` and write `Python/generated_cases.c.h` -**Temporarily also:** - -- `extract_cases.py`: script to extract cases from - `Python/ceval.c` and write them to `Python/bytecodes.c` -- `bytecodes_template.h`: template used by `extract_cases.py` - The DSL for the instruction definitions in `Python/bytecodes.c` is described [here](https://github.com/faster-cpython/ideas/blob/main/3.12/interpreter_definition.md). Note that there is some dummy C code at the top and bottom of the file diff --git a/Tools/cases_generator/bytecodes_template.c b/Tools/cases_generator/bytecodes_template.c deleted file mode 100644 index 31c62b5..0000000 --- a/Tools/cases_generator/bytecodes_template.c +++ /dev/null @@ -1,85 +0,0 @@ -#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" -#include "pycore_long.h" // _PyLong_GetZero() -#include "pycore_object.h" // _PyObject_GC_TRACK() -#include "pycore_moduleobject.h" // PyModuleObject -#include "pycore_opcode.h" // EXTRA_CASES -#include "pycore_pyerrors.h" // _PyErr_Fetch() -#include "pycore_pymem.h" // _PyMem_IsPtrFreed() -#include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_range.h" // _PyRangeIterObject -#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs -#include "pycore_sysmodule.h" // _PySys_Audit() -#include "pycore_tuple.h" // _PyTuple_ITEMS() -#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS - -#include "pycore_dict.h" -#include "dictobject.h" -#include "pycore_frame.h" -#include "opcode.h" -#include "pydtrace.h" -#include "setobject.h" -#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX - -void _PyFloat_ExactDealloc(PyObject *); -void _PyUnicode_ExactDealloc(PyObject *); - -#define SET_TOP(v) (stack_pointer[-1] = (v)) -#define PEEK(n) (stack_pointer[-(n)]) - -#define GETLOCAL(i) (frame->localsplus[i]) - -#define inst(name) case name: -#define family(name) static int family_##name - -#define NAME_ERROR_MSG \ - "name '%.200s' is not defined" - -typedef struct { - PyObject *kwnames; -} CallShape; - -static void -dummy_func( - PyThreadState *tstate, - _PyInterpreterFrame *frame, - unsigned char opcode, - unsigned int oparg, - _Py_atomic_int * const eval_breaker, - _PyCFrame cframe, - PyObject *names, - PyObject *consts, - _Py_CODEUNIT *next_instr, - PyObject **stack_pointer, - CallShape call_shape, - _Py_CODEUNIT *first_instr, - int throwflag, - binaryfunc binary_ops[] -) -{ - switch (opcode) { - - /* BEWARE! - It is essential that any operation that fails must goto error - and that all operation that succeed call DISPATCH() ! */ - -// BEGIN BYTECODES // -// INSERT CASES HERE // -// END BYTECODES // - - } - error:; - exception_unwind:; - handle_eval_breaker:; - resume_frame:; - resume_with_error:; - start_frame:; - unbound_local_error:; -} - -// Families go below this point // - diff --git a/Tools/cases_generator/extract_cases.py b/Tools/cases_generator/extract_cases.py deleted file mode 100644 index 9f1380f..0000000 --- a/Tools/cases_generator/extract_cases.py +++ /dev/null @@ -1,247 +0,0 @@ -"""Extract the main interpreter switch cases.""" - -# Reads cases from ceval.c, writes to bytecodes.c. -# (This file is not meant to be compiled, but it has a .c extension -# so tooling like VS Code can be fooled into thinking it is C code. -# This helps editing and browsing the code.) -# -# The script generate_cases.py regenerates the cases. - -import argparse -import difflib -import dis -import re -import sys - -parser = argparse.ArgumentParser() -parser.add_argument("-i", "--input", type=str, default="Python/ceval.c") -parser.add_argument("-o", "--output", type=str, default="Python/bytecodes.c") -parser.add_argument("-t", "--template", type=str, default="Tools/cases_generator/bytecodes_template.c") -parser.add_argument("-c", "--compare", action="store_true") -parser.add_argument("-q", "--quiet", action="store_true") - - -inverse_specializations = { - specname: familyname - for familyname, specnames in dis._specializations.items() - for specname in specnames -} - - -def eopen(filename, mode="r"): - if filename == "-": - if "r" in mode: - return sys.stdin - else: - return sys.stdout - return open(filename, mode) - - -def leading_whitespace(line): - return len(line) - len(line.lstrip()) - - -def extract_opcode_name(line): - m = re.match(r"\A\s*TARGET\((\w+)\)\s*{\s*\Z", line) - if m: - opcode_name = m.group(1) - if opcode_name not in dis._all_opmap: - raise ValueError(f"error: unknown opcode {opcode_name}") - return opcode_name - raise ValueError(f"error: no opcode in {line.strip()}") - - -def figure_stack_effect(opcode_name): - # Return (i, diff``) where i is the stack effect for oparg=0 - # and diff is the increment for oparg=1. - # If it is irregular or unknown, raise ValueError. - if m := re.match(f"^(\w+)__(\w+)$", opcode_name): - # Super-instruction adds effect of both parts - first, second = m.groups() - se1, incr1 = figure_stack_effect(first) - se2, incr2 = figure_stack_effect(second) - if incr1 or incr2: - raise ValueError(f"irregular stack effect for {opcode_name}") - return se1 + se2, 0 - if opcode_name in inverse_specializations: - # Specialized instruction maps to unspecialized instruction - opcode_name = inverse_specializations[opcode_name] - opcode = dis._all_opmap[opcode_name] - if opcode in dis.hasarg: - try: - se = dis.stack_effect(opcode, 0) - except ValueError as err: - raise ValueError(f"{err} for {opcode_name}") - if dis.stack_effect(opcode, 0, jump=True) != se: - raise ValueError(f"{opcode_name} stack effect depends on jump flag") - if dis.stack_effect(opcode, 0, jump=False) != se: - raise ValueError(f"{opcode_name} stack effect depends on jump flag") - for i in range(1, 257): - if dis.stack_effect(opcode, i) != se: - return figure_variable_stack_effect(opcode_name, opcode, se) - else: - try: - se = dis.stack_effect(opcode) - except ValueError as err: - raise ValueError(f"{err} for {opcode_name}") - if dis.stack_effect(opcode, jump=True) != se: - raise ValueError(f"{opcode_name} stack effect depends on jump flag") - if dis.stack_effect(opcode, jump=False) != se: - raise ValueError(f"{opcode_name} stack effect depends on jump flag") - return se, 0 - - -def figure_variable_stack_effect(opcode_name, opcode, se0): - # Is it a linear progression? - se1 = dis.stack_effect(opcode, 1) - diff = se1 - se0 - for i in range(2, 257): - sei = dis.stack_effect(opcode, i) - if sei - se0 != diff * i: - raise ValueError(f"{opcode_name} has irregular stack effect") - # Assume it's okay for larger oparg values too - return se0, diff - - - -START_MARKER = "/* Start instructions */" # The '{' is on the preceding line. -END_MARKER = "/* End regular instructions */" - -def read_cases(f): - cases = [] - case = None - started = False - # TODO: Count line numbers - for line in f: - stripped = line.strip() - if not started: - if stripped == START_MARKER: - started = True - continue - if stripped == END_MARKER: - break - if stripped.startswith("TARGET("): - if case: - cases.append(case) - indent = " " * leading_whitespace(line) - case = "" - opcode_name = extract_opcode_name(line) - try: - se, diff = figure_stack_effect(opcode_name) - except ValueError as err: - case += f"{indent}// error: {err}\n" - case += f"{indent}inst({opcode_name}) {{\n" - else: - inputs = [] - outputs = [] - if se > 0: - for i in range(se): - outputs.append(f"__{i}") - elif se < 0: - for i in range(-se): - inputs.append(f"__{i}") - if diff > 0: - if diff == 1: - outputs.append(f"__array[oparg]") - else: - outputs.append(f"__array[oparg*{diff}]") - elif diff < 0: - if diff == -1: - inputs.append(f"__array[oparg]") - else: - inputs.append(f"__array[oparg*{-diff}]") - input = ", ".join(inputs) - output = ", ".join(outputs) - case += f"{indent}// stack effect: ({input} -- {output})\n" - case += f"{indent}inst({opcode_name}) {{\n" - else: - if case: - case += line - if case: - cases.append(case) - return cases - - -def write_cases(f, cases): - for case in cases: - caselines = case.splitlines() - while caselines[-1].strip() == "": - caselines.pop() - if caselines[-1].strip() == "}": - caselines.pop() - else: - raise ValueError("case does not end with '}'") - if caselines[-1].strip() == "DISPATCH();": - caselines.pop() - caselines.append(" }") - case = "\n".join(caselines) - print(case + "\n", file=f) - - -def write_families(f): - for opcode, specializations in dis._specializations.items(): - all = [opcode] + specializations - if len(all) <= 3: - members = ', '.join(all) - print(f"family({opcode.lower()}) = {{ {members} }};", file=f) - else: - print(f"family({opcode.lower()}) = {{", file=f) - for i in range(0, len(all), 3): - members = ', '.join(all[i:i+3]) - if i+3 < len(all): - print(f" {members},", file=f) - else: - print(f" {members} }};", file=f) - - -def compare(oldfile, newfile, quiet=False): - with open(oldfile) as f: - oldlines = f.readlines() - for top, line in enumerate(oldlines): - if line.strip() == START_MARKER: - break - else: - print(f"No start marker found in {oldfile}", file=sys.stderr) - return - del oldlines[:top] - for bottom, line in enumerate(oldlines): - if line.strip() == END_MARKER: - break - else: - print(f"No end marker found in {oldfile}", file=sys.stderr) - return - del oldlines[bottom:] - if not quiet: - print( - f"// {oldfile} has {len(oldlines)} lines after stripping top/bottom", - file=sys.stderr, - ) - with open(newfile) as f: - newlines = f.readlines() - if not quiet: - print(f"// {newfile} has {len(newlines)} lines", file=sys.stderr) - for line in difflib.unified_diff(oldlines, newlines, fromfile=oldfile, tofile=newfile): - sys.stdout.write(line) - - -def main(): - args = parser.parse_args() - with eopen(args.input) as f: - cases = read_cases(f) - with open(args.template) as f: - prolog, epilog = f.read().split("// INSERT CASES HERE //", 1) - if not args.quiet: - print(f"// Read {len(cases)} cases from {args.input}", file=sys.stderr) - with eopen(args.output, "w") as f: - f.write(prolog) - write_cases(f, cases) - f.write(epilog) - write_families(f) - if not args.quiet: - print(f"// Wrote {len(cases)} cases to {args.output}", file=sys.stderr) - if args.compare: - compare(args.input, args.output, args.quiet) - - -if __name__ == "__main__": - main() |