Skip to content

GH-103963: Make dis display names of args for intrinsics opcodes #104029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions Include/internal/pycore_intrinsics.h
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
// Auto-generated by Tools/build/generate_opcode_h.py from Lib/opcode.py

/* Unary Functions: */
#define INTRINSIC_1_INVALID 0
#define INTRINSIC_PRINT 1
#define INTRINSIC_IMPORT_STAR 2
#define INTRINSIC_STOPITERATION_ERROR 3
#define INTRINSIC_ASYNC_GEN_WRAP 4
#define INTRINSIC_UNARY_POSITIVE 5
#define INTRINSIC_LIST_TO_TUPLE 6

#define INTRINSIC_PRINT 1
#define INTRINSIC_IMPORT_STAR 2
#define INTRINSIC_STOPITERATION_ERROR 3
#define INTRINSIC_ASYNC_GEN_WRAP 4
#define INTRINSIC_UNARY_POSITIVE 5
#define INTRINSIC_LIST_TO_TUPLE 6

#define MAX_INTRINSIC_1 6
#define MAX_INTRINSIC_1 6


/* Binary Functions: */
#define INTRINSIC_2_INVALID 0
#define INTRINSIC_PREP_RERAISE_STAR 1

#define INTRINSIC_PREP_RERAISE_STAR 1

#define MAX_INTRINSIC_2 1

#define MAX_INTRINSIC_2 1

typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);
typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);

extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[];
extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[];

8 changes: 8 additions & 0 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
_cache_format,
_inline_cache_entries,
_nb_ops,
_intrinsic_1_descs,
_intrinsic_2_descs,
_specializations,
_specialized_instructions,
)
Expand Down Expand Up @@ -42,6 +44,8 @@
SEND = opmap['SEND']
LOAD_ATTR = opmap['LOAD_ATTR']
LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1']
CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2']

CACHE = opmap["CACHE"]

Expand Down Expand Up @@ -506,6 +510,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
if arg & (1<<i))
elif deop == BINARY_OP:
_, argrepr = _nb_ops[arg]
elif deop == CALL_INTRINSIC_1:
argrepr = _intrinsic_1_descs[arg]
elif deop == CALL_INTRINSIC_2:
argrepr = _intrinsic_2_descs[arg]
yield Instruction(_all_opname[op], op,
arg, argval, argrepr,
offset, starts_line, is_jump_target, positions)
Expand Down
15 changes: 15 additions & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,21 @@ def pseudo_op(name, op, real_ops):
("NB_INPLACE_XOR", "^="),
]

_intrinsic_1_descs = [
"INTRINSIC_1_INVALID",
"INTRINSIC_PRINT",
"INTRINSIC_IMPORT_STAR",
"INTRINSIC_STOPITERATION_ERROR",
"INTRINSIC_ASYNC_GEN_WRAP",
"INTRINSIC_UNARY_POSITIVE",
"INTRINSIC_LIST_TO_TUPLE",
]

_intrinsic_2_descs = [
'INTRINSIC_2_INVALID',
'INTRINSIC_PREP_RERAISE_STAR',
]

_specializations = {
"BINARY_OP": [
"BINARY_OP_ADD_FLOAT",
Expand Down
41 changes: 40 additions & 1 deletion Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,35 @@ def wrap_func_w_kwargs():
""" % (wrap_func_w_kwargs.__code__.co_firstlineno,
wrap_func_w_kwargs.__code__.co_firstlineno + 1)

dis_intrinsic_1_2 = """\
0 RESUME 0

1 LOAD_CONST 0 (0)
LOAD_CONST 1 (('*',))
IMPORT_NAME 0 (math)
CALL_INTRINSIC_1 2 (INTRINSIC_IMPORT_STAR)
POP_TOP
RETURN_CONST 2 (None)
"""

dis_intrinsic_1_5 = """\
0 RESUME 0

1 LOAD_NAME 0 (a)
CALL_INTRINSIC_1 5 (INTRINSIC_UNARY_POSITIVE)
RETURN_VALUE
"""

dis_intrinsic_1_6 = """\
0 RESUME 0

1 BUILD_LIST 0
LOAD_NAME 0 (a)
LIST_EXTEND 1
CALL_INTRINSIC_1 6 (INTRINSIC_LIST_TO_TUPLE)
RETURN_VALUE
"""

_BIG_LINENO_FORMAT = """\
1 RESUME 0

Expand Down Expand Up @@ -549,7 +578,7 @@ async def _asyncwith(c):
>> COPY 3
POP_EXCEPT
RERAISE 1
>> CALL_INTRINSIC_1 3
>> CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
RERAISE 1
ExceptionTable:
12 rows
Expand Down Expand Up @@ -942,6 +971,16 @@ def test_kw_names(self):
# Test that value is displayed for KW_NAMES
self.do_disassembly_test(wrap_func_w_kwargs, dis_kw_names)

def test_intrinsic_1(self):
# Test that argrepr is displayed for CALL_INTRINSIC_1
self.do_disassembly_test("from math import *", dis_intrinsic_1_2)
self.do_disassembly_test("+a", dis_intrinsic_1_5)
self.do_disassembly_test("(*a,)", dis_intrinsic_1_6)

def test_intrinsic_2(self):
self.assertIn("CALL_INTRINSIC_2 1 (INTRINSIC_PREP_RERAISE_STAR)",
self.get_disassembly("try: pass\nexcept* Exception: x"))

def test_big_linenos(self):
def func(count):
namespace = {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make :mod:`dis` display the names of the args for :opcode:`CALL_INTRINSIC_*`.
36 changes: 34 additions & 2 deletions Tools/build/generate_opcode_h.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@
#endif // !Py_INTERNAL_OPCODE_H
"""

intrinsic_header = f"""
// Auto-generated by {SCRIPT_NAME} from {PYTHON_OPCODE}

""".lstrip()

intrinsic_footer = """
typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);
typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2);
extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[];
extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[];
"""

DEFINE = "#define {:<38} {:>3}\n"

UINT32_MASK = (1<<32)-1
Expand All @@ -67,7 +79,9 @@ def write_int_array_from_ops(name, ops, out):
assert bits == 0
out.write(f"}};\n")

def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/internal/pycore_opcode.h'):
def main(opcode_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+
Expand Down Expand Up @@ -107,9 +121,11 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
opname_including_specialized[next_op] = name
used[next_op] = True

with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj:
with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj, open(
intrinsicoutfile, "w") as nobj:
fobj.write(header)
iobj.write(internal_header)
nobj.write(intrinsic_header)

for name in opname:
if name in opmap:
Expand Down Expand Up @@ -172,6 +188,22 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
for i, (op, _) in enumerate(opcode["_nb_ops"]):
fobj.write(DEFINE.format(op, i))

nobj.write("/* Unary Functions: */")
nobj.write("\n")
for i, op in enumerate(opcode["_intrinsic_1_descs"]):
nobj.write(DEFINE.format(op, i))
nobj.write("\n")
nobj.write(DEFINE.format("MAX_INTRINSIC_1", i))

nobj.write("\n\n")
nobj.write("/* Binary Functions: */\n")
for i, op in enumerate(opcode["_intrinsic_2_descs"]):
nobj.write(DEFINE.format(op, i))
nobj.write("\n")
nobj.write(DEFINE.format("MAX_INTRINSIC_2", i))

nobj.write(intrinsic_footer)

fobj.write("\n")
fobj.write("/* Defined in Lib/opcode.py */\n")
fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}")
Expand Down