1import dis 2from test.support.import_helper import import_module 3import unittest 4import opcode 5 6_opcode = import_module("_opcode") 7from _opcode import stack_effect 8 9 10class OpListTests(unittest.TestCase): 11 def check_bool_function_result(self, func, ops, expected): 12 for op in ops: 13 if isinstance(op, str): 14 op = dis.opmap[op] 15 with self.subTest(opcode=op, func=func): 16 self.assertIsInstance(func(op), bool) 17 self.assertEqual(func(op), expected) 18 19 def test_invalid_opcodes(self): 20 invalid = [-100, -1, 255, 512, 513, 1000] 21 self.check_bool_function_result(_opcode.is_valid, invalid, False) 22 self.check_bool_function_result(_opcode.has_arg, invalid, False) 23 self.check_bool_function_result(_opcode.has_const, invalid, False) 24 self.check_bool_function_result(_opcode.has_name, invalid, False) 25 self.check_bool_function_result(_opcode.has_jump, invalid, False) 26 self.check_bool_function_result(_opcode.has_free, invalid, False) 27 self.check_bool_function_result(_opcode.has_local, invalid, False) 28 self.check_bool_function_result(_opcode.has_exc, invalid, False) 29 30 def test_is_valid(self): 31 names = [ 32 'CACHE', 33 'POP_TOP', 34 'IMPORT_NAME', 35 'JUMP', 36 'INSTRUMENTED_RETURN_VALUE', 37 ] 38 opcodes = [dis.opmap[opname] for opname in names] 39 self.check_bool_function_result(_opcode.is_valid, opcodes, True) 40 41 def test_oplists(self): 42 def check_function(self, func, expected): 43 for op in [-10, 520]: 44 with self.subTest(opcode=op, func=func): 45 res = func(op) 46 self.assertIsInstance(res, bool) 47 self.assertEqual(res, op in expected) 48 49 check_function(self, _opcode.has_arg, dis.hasarg) 50 check_function(self, _opcode.has_const, dis.hasconst) 51 check_function(self, _opcode.has_name, dis.hasname) 52 check_function(self, _opcode.has_jump, dis.hasjump) 53 check_function(self, _opcode.has_free, dis.hasfree) 54 check_function(self, _opcode.has_local, dis.haslocal) 55 check_function(self, _opcode.has_exc, dis.hasexc) 56 57 58class StackEffectTests(unittest.TestCase): 59 def test_stack_effect(self): 60 self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) 61 self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) 62 self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) 63 self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) 64 self.assertRaises(ValueError, stack_effect, 30000) 65 # All defined opcodes 66 has_arg = dis.hasarg 67 for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): 68 if code >= opcode.MIN_INSTRUMENTED_OPCODE: 69 continue 70 with self.subTest(opname=name): 71 stack_effect(code) 72 stack_effect(code, 0) 73 # All not defined opcodes 74 for code in set(range(256)) - set(dis.opmap.values()): 75 with self.subTest(opcode=code): 76 self.assertRaises(ValueError, stack_effect, code) 77 self.assertRaises(ValueError, stack_effect, code, 0) 78 79 def test_stack_effect_jump(self): 80 FOR_ITER = dis.opmap['FOR_ITER'] 81 self.assertEqual(stack_effect(FOR_ITER, 0), 1) 82 self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) 83 self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1) 84 JUMP_FORWARD = dis.opmap['JUMP_FORWARD'] 85 self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0) 86 self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0) 87 self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=False), 0) 88 # All defined opcodes 89 has_arg = dis.hasarg 90 has_exc = dis.hasexc 91 has_jump = dis.hasjabs + dis.hasjrel 92 for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()): 93 if code >= opcode.MIN_INSTRUMENTED_OPCODE: 94 continue 95 with self.subTest(opname=name): 96 if code not in has_arg: 97 common = stack_effect(code) 98 jump = stack_effect(code, jump=True) 99 nojump = stack_effect(code, jump=False) 100 else: 101 common = stack_effect(code, 0) 102 jump = stack_effect(code, 0, jump=True) 103 nojump = stack_effect(code, 0, jump=False) 104 if code in has_jump or code in has_exc: 105 self.assertEqual(common, max(jump, nojump)) 106 else: 107 self.assertEqual(jump, common) 108 self.assertEqual(nojump, common) 109 110 111class SpecializationStatsTests(unittest.TestCase): 112 def test_specialization_stats(self): 113 stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"] 114 specialized_opcodes = [ 115 op.lower() 116 for op in opcode._specializations 117 if opcode._inline_cache_entries.get(op, 0) 118 ] 119 self.assertIn('load_attr', specialized_opcodes) 120 self.assertIn('binary_subscr', specialized_opcodes) 121 122 stats = _opcode.get_specialization_stats() 123 if stats is not None: 124 self.assertIsInstance(stats, dict) 125 self.assertCountEqual(stats.keys(), specialized_opcodes) 126 self.assertCountEqual( 127 stats['load_attr'].keys(), 128 stat_names + ['failure_kinds']) 129 for sn in stat_names: 130 self.assertIsInstance(stats['load_attr'][sn], int) 131 self.assertIsInstance( 132 stats['load_attr']['failure_kinds'], 133 tuple) 134 for v in stats['load_attr']['failure_kinds']: 135 self.assertIsInstance(v, int) 136 137 138if __name__ == "__main__": 139 unittest.main() 140