gh-105481: expose opcode metadata via the _opcode module (#106688)

This commit is contained in:
Irit Katriel 2023-07-14 18:41:52 +01:00 committed by GitHub
parent 243fdcb40e
commit 6a70edf24c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 558 additions and 21 deletions

View file

@ -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)