Skip to content

Commit d8e6db8

Browse files
committed
Update from Brandt's code review
- Change family syntax to `family(NAME) = {OP1, OP2, ...};` - Some cleanups in parser.py and generate_cases.py - Fixes to bytecodes.c to reduce red wiggles in VS Code
1 parent 6ea380f commit d8e6db8

File tree

5 files changed

+150
-75
lines changed

5 files changed

+150
-75
lines changed

Python/bytecodes.c

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,48 @@
11
#include "Python.h"
2-
3-
#include "opcode.h"
4-
#include "pycore_atomic.h"
2+
#include "pycore_abstract.h" // _PyIndex_Check()
3+
#include "pycore_call.h" // _PyObject_FastCallDictTstate()
4+
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
5+
#include "pycore_code.h"
6+
#include "pycore_function.h"
7+
#include "pycore_long.h" // _PyLong_GetZero()
8+
#include "pycore_object.h" // _PyObject_GC_TRACK()
9+
#include "pycore_moduleobject.h" // PyModuleObject
10+
#include "pycore_opcode.h" // EXTRA_CASES
11+
#include "pycore_pyerrors.h" // _PyErr_Fetch()
12+
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
13+
#include "pycore_pystate.h" // _PyInterpreterState_GET()
14+
#include "pycore_range.h" // _PyRangeIterObject
15+
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
16+
#include "pycore_sysmodule.h" // _PySys_Audit()
17+
#include "pycore_tuple.h" // _PyTuple_ITEMS()
18+
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
19+
20+
#include "pycore_dict.h"
21+
#include "dictobject.h"
522
#include "pycore_frame.h"
23+
#include "opcode.h"
24+
#include "pydtrace.h"
25+
#include "setobject.h"
26+
#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
627

728
void _PyFloat_ExactDealloc(PyObject *);
829
void _PyUnicode_ExactDealloc(PyObject *);
930

1031
#define SET_TOP(v) (stack_pointer[-1] = (v))
32+
#define PEEK(n) (stack_pointer[-(n)])
33+
1134
#define GETLOCAL(i) (frame->localsplus[i])
1235

13-
#define inst(name, stack_effect) case name:
36+
#define inst(name) case name:
1437
#define family(name) static int family_##name
1538

39+
#define NAME_ERROR_MSG \
40+
"name '%.200s' is not defined"
41+
42+
typedef struct {
43+
PyObject *kwnames;
44+
} CallShape;
45+
1646
static void
1747
dummy_func(
1848
PyThreadState *tstate,
@@ -24,11 +54,19 @@ dummy_func(
2454
PyObject *names,
2555
PyObject *consts,
2656
_Py_CODEUNIT *next_instr,
27-
PyObject **stack_pointer
57+
PyObject **stack_pointer,
58+
CallShape call_shape,
59+
_Py_CODEUNIT *first_instr,
60+
int throwflag,
61+
binaryfunc binary_ops[]
2862
)
2963
{
3064
switch (opcode) {
3165

66+
/* BEWARE!
67+
It is essential that any operation that fails must goto error
68+
and that all operation that succeed call DISPATCH() ! */
69+
3270
// BEGIN BYTECODES //
3371
// stack effect: ( -- )
3472
inst(NOP) {
@@ -3924,56 +3962,60 @@ dummy_func(
39243962
// END BYTECODES //
39253963

39263964
}
3965+
error:;
3966+
exception_unwind:;
39273967
handle_eval_breaker:;
3968+
resume_frame:;
3969+
resume_with_error:;
3970+
start_frame:;
39283971
unbound_local_error:;
3929-
error:;
39303972
}
39313973

39323974
// Families go below this point //
39333975

3934-
family(binary_op) =
3976+
family(binary_op) = {
39353977
BINARY_OP, BINARY_OP_ADAPTIVE, BINARY_OP_ADD_FLOAT,
39363978
BINARY_OP_ADD_INT, BINARY_OP_ADD_UNICODE, BINARY_OP_INPLACE_ADD_UNICODE,
3937-
BINARY_OP_MULTIPLY_FLOAT, BINARY_OP_MULTIPLY_INT, BINARY_OP_SUBTRACT_FLOAT;
3938-
BINARY_OP_SUBTRACT_INT;
3939-
family(binary_subscr) =
3979+
BINARY_OP_MULTIPLY_FLOAT, BINARY_OP_MULTIPLY_INT, BINARY_OP_SUBTRACT_FLOAT,
3980+
BINARY_OP_SUBTRACT_INT };
3981+
family(binary_subscr) = {
39403982
BINARY_SUBSCR, BINARY_SUBSCR_ADAPTIVE, BINARY_SUBSCR_DICT,
3941-
BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_LIST_INT, BINARY_SUBSCR_TUPLE_INT;
3942-
family(call) =
3983+
BINARY_SUBSCR_GETITEM, BINARY_SUBSCR_LIST_INT, BINARY_SUBSCR_TUPLE_INT };
3984+
family(call) = {
39433985
CALL, CALL_ADAPTIVE, CALL_PY_EXACT_ARGS,
39443986
CALL_PY_WITH_DEFAULTS, CALL_BOUND_METHOD_EXACT_ARGS, CALL_BUILTIN_CLASS,
39453987
CALL_BUILTIN_FAST_WITH_KEYWORDS, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, CALL_NO_KW_BUILTIN_FAST,
39463988
CALL_NO_KW_BUILTIN_O, CALL_NO_KW_ISINSTANCE, CALL_NO_KW_LEN,
39473989
CALL_NO_KW_LIST_APPEND, CALL_NO_KW_METHOD_DESCRIPTOR_FAST, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS,
3948-
CALL_NO_KW_METHOD_DESCRIPTOR_O, CALL_NO_KW_STR_1, CALL_NO_KW_TUPLE_1;
3949-
CALL_NO_KW_TYPE_1;
3950-
family(compare_op) =
3990+
CALL_NO_KW_METHOD_DESCRIPTOR_O, CALL_NO_KW_STR_1, CALL_NO_KW_TUPLE_1,
3991+
CALL_NO_KW_TYPE_1 };
3992+
family(compare_op) = {
39513993
COMPARE_OP, COMPARE_OP_ADAPTIVE, COMPARE_OP_FLOAT_JUMP,
3952-
COMPARE_OP_INT_JUMP, COMPARE_OP_STR_JUMP;
3953-
family(extended_arg) = EXTENDED_ARG, EXTENDED_ARG_QUICK;
3954-
family(for_iter) =
3955-
FOR_ITER, FOR_ITER_ADAPTIVE, FOR_ITER_LIST;
3956-
FOR_ITER_RANGE;
3957-
family(jump_backward) = JUMP_BACKWARD, JUMP_BACKWARD_QUICK;
3958-
family(load_attr) =
3994+
COMPARE_OP_INT_JUMP, COMPARE_OP_STR_JUMP };
3995+
family(extended_arg) = { EXTENDED_ARG, EXTENDED_ARG_QUICK };
3996+
family(for_iter) = {
3997+
FOR_ITER, FOR_ITER_ADAPTIVE, FOR_ITER_LIST,
3998+
FOR_ITER_RANGE };
3999+
family(jump_backward) = { JUMP_BACKWARD, JUMP_BACKWARD_QUICK };
4000+
family(load_attr) = {
39594001
LOAD_ATTR, LOAD_ATTR_ADAPTIVE, LOAD_ATTR_CLASS,
39604002
LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_MODULE,
39614003
LOAD_ATTR_PROPERTY, LOAD_ATTR_SLOT, LOAD_ATTR_WITH_HINT,
3962-
LOAD_ATTR_METHOD_LAZY_DICT, LOAD_ATTR_METHOD_NO_DICT, LOAD_ATTR_METHOD_WITH_DICT;
3963-
LOAD_ATTR_METHOD_WITH_VALUES;
3964-
family(load_const) = LOAD_CONST, LOAD_CONST__LOAD_FAST;
3965-
family(load_fast) = LOAD_FAST, LOAD_FAST__LOAD_CONST, LOAD_FAST__LOAD_FAST;
3966-
family(load_global) =
3967-
LOAD_GLOBAL, LOAD_GLOBAL_ADAPTIVE, LOAD_GLOBAL_BUILTIN;
3968-
LOAD_GLOBAL_MODULE;
3969-
family(resume) = RESUME, RESUME_QUICK;
3970-
family(store_attr) =
4004+
LOAD_ATTR_METHOD_LAZY_DICT, LOAD_ATTR_METHOD_NO_DICT, LOAD_ATTR_METHOD_WITH_DICT,
4005+
LOAD_ATTR_METHOD_WITH_VALUES };
4006+
family(load_const) = { LOAD_CONST, LOAD_CONST__LOAD_FAST };
4007+
family(load_fast) = { LOAD_FAST, LOAD_FAST__LOAD_CONST, LOAD_FAST__LOAD_FAST };
4008+
family(load_global) = {
4009+
LOAD_GLOBAL, LOAD_GLOBAL_ADAPTIVE, LOAD_GLOBAL_BUILTIN,
4010+
LOAD_GLOBAL_MODULE };
4011+
family(resume) = { RESUME, RESUME_QUICK };
4012+
family(store_attr) = {
39714013
STORE_ATTR, STORE_ATTR_ADAPTIVE, STORE_ATTR_INSTANCE_VALUE,
3972-
STORE_ATTR_SLOT, STORE_ATTR_WITH_HINT;
3973-
family(store_fast) = STORE_FAST, STORE_FAST__LOAD_FAST, STORE_FAST__STORE_FAST;
3974-
family(store_subscr) =
3975-
STORE_SUBSCR, STORE_SUBSCR_ADAPTIVE, STORE_SUBSCR_DICT;
3976-
STORE_SUBSCR_LIST_INT;
3977-
family(unpack_sequence) =
4014+
STORE_ATTR_SLOT, STORE_ATTR_WITH_HINT };
4015+
family(store_fast) = { STORE_FAST, STORE_FAST__LOAD_FAST, STORE_FAST__STORE_FAST };
4016+
family(store_subscr) = {
4017+
STORE_SUBSCR, STORE_SUBSCR_ADAPTIVE, STORE_SUBSCR_DICT,
4018+
STORE_SUBSCR_LIST_INT };
4019+
family(unpack_sequence) = {
39784020
UNPACK_SEQUENCE, UNPACK_SEQUENCE_ADAPTIVE, UNPACK_SEQUENCE_LIST,
3979-
UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_TWO_TUPLE;
4021+
UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_TWO_TUPLE };

Tools/cases_generator/bytecodes_template.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,48 @@
11
#include "Python.h"
2+
#include "pycore_abstract.h" // _PyIndex_Check()
3+
#include "pycore_call.h" // _PyObject_FastCallDictTstate()
4+
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
5+
#include "pycore_code.h"
6+
#include "pycore_function.h"
7+
#include "pycore_long.h" // _PyLong_GetZero()
8+
#include "pycore_object.h" // _PyObject_GC_TRACK()
9+
#include "pycore_moduleobject.h" // PyModuleObject
10+
#include "pycore_opcode.h" // EXTRA_CASES
11+
#include "pycore_pyerrors.h" // _PyErr_Fetch()
12+
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
13+
#include "pycore_pystate.h" // _PyInterpreterState_GET()
14+
#include "pycore_range.h" // _PyRangeIterObject
15+
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
16+
#include "pycore_sysmodule.h" // _PySys_Audit()
17+
#include "pycore_tuple.h" // _PyTuple_ITEMS()
18+
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
219

3-
#include "opcode.h"
4-
#include "pycore_atomic.h"
20+
#include "pycore_dict.h"
21+
#include "dictobject.h"
522
#include "pycore_frame.h"
23+
#include "opcode.h"
24+
#include "pydtrace.h"
25+
#include "setobject.h"
26+
#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
627

728
void _PyFloat_ExactDealloc(PyObject *);
829
void _PyUnicode_ExactDealloc(PyObject *);
930

1031
#define SET_TOP(v) (stack_pointer[-1] = (v))
32+
#define PEEK(n) (stack_pointer[-(n)])
33+
1134
#define GETLOCAL(i) (frame->localsplus[i])
1235

13-
#define inst(name, stack_effect) case name:
36+
#define inst(name) case name:
1437
#define family(name) static int family_##name
1538

39+
#define NAME_ERROR_MSG \
40+
"name '%.200s' is not defined"
41+
42+
typedef struct {
43+
PyObject *kwnames;
44+
} CallShape;
45+
1646
static void
1747
dummy_func(
1848
PyThreadState *tstate,
@@ -24,19 +54,31 @@ dummy_func(
2454
PyObject *names,
2555
PyObject *consts,
2656
_Py_CODEUNIT *next_instr,
27-
PyObject **stack_pointer
57+
PyObject **stack_pointer,
58+
CallShape call_shape,
59+
_Py_CODEUNIT *first_instr,
60+
int throwflag,
61+
binaryfunc binary_ops[]
2862
)
2963
{
3064
switch (opcode) {
3165

66+
/* BEWARE!
67+
It is essential that any operation that fails must goto error
68+
and that all operation that succeed call DISPATCH() ! */
69+
3270
// BEGIN BYTECODES //
3371
// INSERT CASES HERE //
3472
// END BYTECODES //
3573

3674
}
75+
error:;
76+
exception_unwind:;
3777
handle_eval_breaker:;
78+
resume_frame:;
79+
resume_with_error:;
80+
start_frame:;
3881
unbound_local_error:;
39-
error:;
4082
}
4183

4284
// Families go below this point //

Tools/cases_generator/extract_cases.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,16 @@ def write_families(f):
182182
for opcode, specializations in dis._specializations.items():
183183
all = [opcode] + specializations
184184
if len(all) <= 3:
185-
members = ', '.join([opcode] + specializations)
186-
print(f"family({opcode.lower()}) = {members};", file=f)
185+
members = ', '.join(all)
186+
print(f"family({opcode.lower()}) = {{ {members} }};", file=f)
187187
else:
188-
print(f"family({opcode.lower()}) =", file=f)
188+
print(f"family({opcode.lower()}) = {{", file=f)
189189
for i in range(0, len(all), 3):
190190
members = ', '.join(all[i:i+3])
191-
if i+4 < len(all):
191+
if i+3 < len(all):
192192
print(f" {members},", file=f)
193193
else:
194-
print(f" {members};", file=f)
194+
print(f" {members} }};", file=f)
195195

196196

197197
def compare(oldfile, newfile, quiet=False):

Tools/cases_generator/generate_cases.py

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
# TODO: Reuse C generation framework from deepfreeze.py?
66

77
import argparse
8-
from dataclasses import dataclass
9-
import re
8+
import io
109
import sys
1110

1211
import parser
12+
from parser import InstDef
1313

1414
arg_parser = argparse.ArgumentParser()
1515
arg_parser.add_argument("-i", "--input", type=str, default="Python/bytecodes.c")
@@ -18,7 +18,7 @@
1818
arg_parser.add_argument("-q", "--quiet", action="store_true")
1919

2020

21-
def eopen(filename, mode="r"):
21+
def eopen(filename: str, mode: str = "r"):
2222
if filename == "-":
2323
if "r" in mode:
2424
return sys.stdin
@@ -27,26 +27,14 @@ def eopen(filename, mode="r"):
2727
return open(filename, mode)
2828

2929

30-
def leading_whitespace(line):
31-
return len(line) - len(line.lstrip())
32-
33-
34-
@dataclass
35-
class Instruction:
36-
opcode_name: str
37-
inputs: list[str]
38-
outputs: list[str]
39-
block: parser.Block
40-
41-
42-
def parse_cases(src: str, filename: str|None = None) -> tuple[list[Instruction], list[parser.Family]]:
30+
def parse_cases(src: str, filename: str|None = None) -> tuple[list[InstDef], list[parser.Family]]:
4331
psr = parser.Parser(src, filename=filename)
44-
instrs: list[Instruction] = []
32+
instrs: list[InstDef] = []
4533
families: list[parser.Family] = []
4634
while not psr.eof():
4735
if inst := psr.inst_def():
4836
assert inst.block
49-
instrs.append(Instruction(inst.name, inst.inputs, inst.outputs, inst.block))
37+
instrs.append(InstDef(inst.name, inst.inputs, inst.outputs, inst.block))
5038
elif fam := psr.family_def():
5139
families.append(fam)
5240
else:
@@ -72,16 +60,17 @@ def always_exits(block: parser.Block) -> bool:
7260
return line.startswith(("goto ", "return ", "DISPATCH", "GO_TO_", "Py_UNREACHABLE()"))
7361

7462

75-
def write_cases(f, instrs):
63+
def write_cases(f: io.TextIOBase, instrs: list[InstDef]):
7664
indent = " "
7765
f.write("// This file is generated by Tools/scripts/generate_cases.py\n")
7866
f.write("// Do not edit!\n")
7967
for instr in instrs:
80-
assert isinstance(instr, Instruction)
81-
f.write(f"\n{indent}TARGET({instr.opcode_name}) {{\n")
68+
assert isinstance(instr, InstDef)
69+
f.write(f"\n{indent}TARGET({instr.name}) {{\n")
8270
# input = ", ".join(instr.inputs)
8371
# output = ", ".join(instr.outputs)
8472
# f.write(f"{indent} // {input} -- {output}\n")
73+
assert instr.block
8574
blocklines = instr.block.text.splitlines(True)
8675
# Remove blank lines from ends
8776
while blocklines and not blocklines[0].strip():
@@ -99,6 +88,7 @@ def write_cases(f, instrs):
9988
# Write the body
10089
for line in blocklines:
10190
f.write(line)
91+
assert instr.block
10292
if not always_exits(instr.block):
10393
f.write(f"{indent} DISPATCH();\n")
10494
# Write trailing '}'
@@ -113,6 +103,7 @@ def main():
113103
end = srclines.index("// END BYTECODES //")
114104
src = "\n".join(srclines[begin+1 : end])
115105
instrs, families = parse_cases(src, filename=args.input)
106+
ninstrs = nfamilies = 0
116107
if not args.quiet:
117108
ninstrs = len(instrs)
118109
nfamilies = len(families)

0 commit comments

Comments
 (0)