From e8e151d4715839f785ff853c77594d7302b40266 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 20 Jun 2024 07:07:24 -0700 Subject: [PATCH] gh-120780: Show attribute name for LOAD_SPECIAL in dis output (#120781) --- Lib/dis.py | 4 +++ Lib/opcode.py | 1 + Lib/test/test_dis.py | 12 ++++---- ...-06-19-23-08-25.gh-issue-120780.0Omopb.rst | 1 + Modules/_opcode.c | 28 +++++++++++++++++++ Modules/clinic/_opcode.c.h | 20 ++++++++++++- 6 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst diff --git a/Lib/dis.py b/Lib/dis.py index f5bb7976b5f..bb922b786f5 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -14,6 +14,7 @@ from opcode import ( _common_constants, _intrinsic_1_descs, _intrinsic_2_descs, + _special_method_names, _specializations, _specialized_opmap, ) @@ -46,6 +47,7 @@ LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR'] CALL_INTRINSIC_1 = opmap['CALL_INTRINSIC_1'] CALL_INTRINSIC_2 = opmap['CALL_INTRINSIC_2'] LOAD_COMMON_CONSTANT = opmap['LOAD_COMMON_CONSTANT'] +LOAD_SPECIAL = opmap['LOAD_SPECIAL'] LOAD_FAST_LOAD_FAST = opmap['LOAD_FAST_LOAD_FAST'] STORE_FAST_LOAD_FAST = opmap['STORE_FAST_LOAD_FAST'] STORE_FAST_STORE_FAST = opmap['STORE_FAST_STORE_FAST'] @@ -609,6 +611,8 @@ class ArgResolver: argrepr = obj.__name__ else: argrepr = repr(obj) + elif deop == LOAD_SPECIAL: + argrepr = _special_method_names[arg] return argval, argrepr def get_instructions(x, *, first_line=None, show_caches=None, adaptive=False): diff --git a/Lib/opcode.py b/Lib/opcode.py index 85c0834c698..2698609cd56 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -36,6 +36,7 @@ hasexc = [op for op in opmap.values() if _opcode.has_exc(op)] _intrinsic_1_descs = _opcode.get_intrinsic1_descs() _intrinsic_2_descs = _opcode.get_intrinsic2_descs() +_special_method_names = _opcode.get_special_method_names() _common_constants = [AssertionError, NotImplementedError] _nb_ops = _opcode.get_nb_ops() diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index ffbeea2ef56..ab1c48f9b25 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -481,10 +481,10 @@ dis_with = """\ %4d LOAD_FAST 0 (c) COPY 1 - LOAD_SPECIAL 1 + LOAD_SPECIAL 1 (__exit__) SWAP 2 SWAP 3 - LOAD_SPECIAL 0 + LOAD_SPECIAL 0 (__enter__) CALL 0 L1: POP_TOP @@ -543,10 +543,10 @@ dis_asyncwith = """\ %4d LOAD_FAST 0 (c) COPY 1 - LOAD_SPECIAL 3 + LOAD_SPECIAL 3 (__aexit__) SWAP 2 SWAP 3 - LOAD_SPECIAL 2 + LOAD_SPECIAL 2 (__aenter__) CALL 0 GET_AWAITABLE 1 LOAD_CONST 0 (None) @@ -1738,10 +1738,10 @@ expected_opinfo_jumpy = [ Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), Instruction(opname='LOAD_FAST', opcode=83, arg=0, argval='i', argrepr='i', offset=242, start_offset=242, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), Instruction(opname='COPY', opcode=58, arg=1, argval=1, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_SPECIAL', opcode=91, arg=1, argval=1, argrepr='', offset=246, start_offset=246, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_SPECIAL', opcode=91, arg=1, argval=1, argrepr='__exit__', offset=246, start_offset=246, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), Instruction(opname='SWAP', opcode=114, arg=2, argval=2, argrepr='', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), Instruction(opname='SWAP', opcode=114, arg=3, argval=3, argrepr='', offset=250, start_offset=250, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_SPECIAL', opcode=91, arg=0, argval=0, argrepr='', offset=252, start_offset=252, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_SPECIAL', opcode=91, arg=0, argval=0, argrepr='__enter__', offset=252, start_offset=252, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), Instruction(opname='CALL', opcode=50, arg=0, argval=0, argrepr='', offset=254, start_offset=254, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), Instruction(opname='STORE_FAST', opcode=109, arg=1, argval='dodgy', argrepr='dodgy', offset=262, start_offset=262, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), Instruction(opname='LOAD_GLOBAL', opcode=89, arg=3, argval='print', argrepr='print + NULL', offset=264, start_offset=264, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), diff --git a/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst b/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst new file mode 100644 index 00000000000..df3cfbcdbd2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-06-19-23-08-25.gh-issue-120780.0Omopb.rst @@ -0,0 +1 @@ +Show string value of LOAD_SPECIAL oparg in :mod:`dis` output. diff --git a/Modules/_opcode.c b/Modules/_opcode.c index cc72cb170ce..d666f634757 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -5,6 +5,7 @@ #include "Python.h" #include "compile.h" #include "opcode.h" +#include "internal/pycore_ceval.h" #include "internal/pycore_code.h" #include "internal/pycore_compile.h" #include "internal/pycore_intrinsics.h" @@ -349,6 +350,32 @@ _opcode_get_intrinsic2_descs_impl(PyObject *module) /*[clinic input] +_opcode.get_special_method_names + +Return a list of special method names. +[clinic start generated code]*/ + +static PyObject * +_opcode_get_special_method_names_impl(PyObject *module) +/*[clinic end generated code: output=fce72614cd988d17 input=25f2115560bdf163]*/ +{ + PyObject *list = PyList_New(SPECIAL_MAX + 1); + if (list == NULL) { + return NULL; + } + for (int i=0; i <= SPECIAL_MAX; i++) { + PyObject *name = _Py_SpecialMethods[i].name; + if (name == NULL) { + Py_DECREF(list); + return NULL; + } + PyList_SET_ITEM(list, i, name); + } + return list; +} + +/*[clinic input] + _opcode.get_executor code: object @@ -392,6 +419,7 @@ opcode_functions[] = { _OPCODE_GET_INTRINSIC1_DESCS_METHODDEF _OPCODE_GET_INTRINSIC2_DESCS_METHODDEF _OPCODE_GET_EXECUTOR_METHODDEF + _OPCODE_GET_SPECIAL_METHOD_NAMES_METHODDEF {NULL, NULL, 0, NULL} }; diff --git a/Modules/clinic/_opcode.c.h b/Modules/clinic/_opcode.c.h index fb90fb8e32f..32ac9521a2b 100644 --- a/Modules/clinic/_opcode.c.h +++ b/Modules/clinic/_opcode.c.h @@ -669,6 +669,24 @@ _opcode_get_intrinsic2_descs(PyObject *module, PyObject *Py_UNUSED(ignored)) return _opcode_get_intrinsic2_descs_impl(module); } +PyDoc_STRVAR(_opcode_get_special_method_names__doc__, +"get_special_method_names($module, /)\n" +"--\n" +"\n" +"Return a list of special method names."); + +#define _OPCODE_GET_SPECIAL_METHOD_NAMES_METHODDEF \ + {"get_special_method_names", (PyCFunction)_opcode_get_special_method_names, METH_NOARGS, _opcode_get_special_method_names__doc__}, + +static PyObject * +_opcode_get_special_method_names_impl(PyObject *module); + +static PyObject * +_opcode_get_special_method_names(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _opcode_get_special_method_names_impl(module); +} + PyDoc_STRVAR(_opcode_get_executor__doc__, "get_executor($module, /, code, offset)\n" "--\n" @@ -728,4 +746,4 @@ _opcode_get_executor(PyObject *module, PyObject *const *args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=2dbb31b041b49c8f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3b4d4f32eedd636e input=a9049054013a1b77]*/