mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
gh-105481: expose opcode metadata via the _opcode module (#106688)
This commit is contained in:
parent
243fdcb40e
commit
6a70edf24c
9 changed files with 558 additions and 21 deletions
|
@ -9,6 +9,70 @@ from _opcode import stack_effect
|
|||
|
||||
class OpcodeTests(unittest.TestCase):
|
||||
|
||||
def check_bool_function_result(self, func, ops, expected):
|
||||
for op in ops:
|
||||
if isinstance(op, str):
|
||||
op = dis.opmap[op]
|
||||
with self.subTest(opcode=op, func=func):
|
||||
self.assertIsInstance(func(op), bool)
|
||||
self.assertEqual(func(op), expected)
|
||||
|
||||
def test_invalid_opcodes(self):
|
||||
invalid = [-100, -1, 255, 512, 513, 1000]
|
||||
self.check_bool_function_result(_opcode.is_valid, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_arg, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_const, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_name, invalid, False)
|
||||
self.check_bool_function_result(_opcode.has_jump, invalid, False)
|
||||
|
||||
def test_is_valid(self):
|
||||
names = [
|
||||
'CACHE',
|
||||
'POP_TOP',
|
||||
'IMPORT_NAME',
|
||||
'JUMP',
|
||||
'INSTRUMENTED_RETURN_VALUE',
|
||||
]
|
||||
opcodes = [dis.opmap[opname] for opname in names]
|
||||
self.check_bool_function_result(_opcode.is_valid, opcodes, True)
|
||||
|
||||
def test_has_arg(self):
|
||||
has_arg = ['SWAP', 'LOAD_FAST', 'INSTRUMENTED_POP_JUMP_IF_TRUE', 'JUMP']
|
||||
no_arg = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
|
||||
self.check_bool_function_result(_opcode.has_arg, has_arg, True)
|
||||
self.check_bool_function_result(_opcode.has_arg, no_arg, False)
|
||||
|
||||
def test_has_const(self):
|
||||
has_const = ['LOAD_CONST', 'RETURN_CONST', 'KW_NAMES']
|
||||
no_const = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
|
||||
self.check_bool_function_result(_opcode.has_const, has_const, True)
|
||||
self.check_bool_function_result(_opcode.has_const, no_const, False)
|
||||
|
||||
def test_has_name(self):
|
||||
has_name = ['STORE_NAME', 'DELETE_ATTR', 'STORE_GLOBAL', 'IMPORT_FROM',
|
||||
'LOAD_FROM_DICT_OR_GLOBALS']
|
||||
no_name = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
|
||||
self.check_bool_function_result(_opcode.has_name, has_name, True)
|
||||
self.check_bool_function_result(_opcode.has_name, no_name, False)
|
||||
|
||||
def test_has_jump(self):
|
||||
has_jump = ['FOR_ITER', 'JUMP_FORWARD', 'JUMP', 'POP_JUMP_IF_TRUE', 'SEND']
|
||||
no_jump = ['SETUP_WITH', 'POP_TOP', 'NOP', 'CACHE']
|
||||
self.check_bool_function_result(_opcode.has_jump, has_jump, True)
|
||||
self.check_bool_function_result(_opcode.has_jump, no_jump, False)
|
||||
|
||||
# the following test is part of the refactor, it will be removed soon
|
||||
def test_against_legacy_bool_values(self):
|
||||
# limiting to ops up to ENTER_EXECUTOR, because everything after that
|
||||
# is not currently categorized correctly in opcode.py.
|
||||
for op in range(0, opcode.opmap['ENTER_EXECUTOR']):
|
||||
with self.subTest(op=op):
|
||||
if opcode.opname[op] != f'<{op}>':
|
||||
self.assertEqual(op in dis.hasarg, _opcode.has_arg(op))
|
||||
self.assertEqual(op in dis.hasconst, _opcode.has_const(op))
|
||||
self.assertEqual(op in dis.hasname, _opcode.has_name(op))
|
||||
self.assertEqual(op in dis.hasjrel, _opcode.has_jump(op))
|
||||
|
||||
def test_stack_effect(self):
|
||||
self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
|
||||
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue