Skip to content

Commit

Permalink
GH-103963: Make dis display names of args for intrinsics opcodes (#10…
Browse files Browse the repository at this point in the history
  • Loading branch information
jkchandalia authored May 3, 2023
1 parent 65a49c6 commit 872cbc6
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 17 deletions.
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

0 comments on commit 872cbc6

Please sign in to comment.