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 OpcodeTests(unittest.TestCase):
11
12    def test_stack_effect(self):
13        self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
14        self.assertEqual(stack_effect(dis.opmap['DUP_TOP_TWO']), 2)
15        self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
16        self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
17        self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)
18        self.assertRaises(ValueError, stack_effect, 30000)
19        self.assertRaises(ValueError, stack_effect, dis.opmap['BUILD_SLICE'])
20        self.assertRaises(ValueError, stack_effect, dis.opmap['POP_TOP'], 0)
21        # All defined opcodes
22        for name, code in dis.opmap.items():
23            with self.subTest(opname=name):
24                if code < dis.HAVE_ARGUMENT:
25                    stack_effect(code)
26                    self.assertRaises(ValueError, stack_effect, code, 0)
27                else:
28                    stack_effect(code, 0)
29                    self.assertRaises(ValueError, stack_effect, code)
30        # All not defined opcodes
31        for code in set(range(256)) - set(dis.opmap.values()):
32            with self.subTest(opcode=code):
33                self.assertRaises(ValueError, stack_effect, code)
34                self.assertRaises(ValueError, stack_effect, code, 0)
35
36    def test_stack_effect_jump(self):
37        JUMP_IF_TRUE_OR_POP = dis.opmap['JUMP_IF_TRUE_OR_POP']
38        self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0)
39        self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0)
40        self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1)
41        FOR_ITER = dis.opmap['FOR_ITER']
42        self.assertEqual(stack_effect(FOR_ITER, 0), 1)
43        self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), -1)
44        self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1)
45        JUMP_FORWARD = dis.opmap['JUMP_FORWARD']
46        self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0)
47        self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0)
48        self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=False), 0)
49        # All defined opcodes
50        has_jump = dis.hasjabs + dis.hasjrel
51        for name, code in dis.opmap.items():
52            with self.subTest(opname=name):
53                if code < dis.HAVE_ARGUMENT:
54                    common = stack_effect(code)
55                    jump = stack_effect(code, jump=True)
56                    nojump = stack_effect(code, jump=False)
57                else:
58                    common = stack_effect(code, 0)
59                    jump = stack_effect(code, 0, jump=True)
60                    nojump = stack_effect(code, 0, jump=False)
61                if code in has_jump:
62                    self.assertEqual(common, max(jump, nojump))
63                else:
64                    self.assertEqual(jump, common)
65                    self.assertEqual(nojump, common)
66
67
68class SpecializationStatsTests(unittest.TestCase):
69    def test_specialization_stats(self):
70        stat_names = opcode._specialization_stats
71
72        specialized_opcodes = [
73            op[:-len("_ADAPTIVE")].lower() for
74            op in opcode._specialized_instructions
75            if op.endswith("_ADAPTIVE")]
76        self.assertIn('load_attr', specialized_opcodes)
77        self.assertIn('binary_subscr', specialized_opcodes)
78
79        stats = _opcode.get_specialization_stats()
80        if stats is not None:
81            self.assertIsInstance(stats, dict)
82            self.assertCountEqual(stats.keys(), specialized_opcodes)
83            self.assertCountEqual(
84                stats['load_attr'].keys(),
85                stat_names + ['specialization_failure_kinds'])
86            for sn in stat_names:
87                self.assertIsInstance(stats['load_attr'][sn], int)
88            self.assertIsInstance(
89                stats['load_attr']['specialization_failure_kinds'],
90                tuple)
91            for v in stats['load_attr']['specialization_failure_kinds']:
92                self.assertIsInstance(v, int)
93
94
95if __name__ == "__main__":
96    unittest.main()
97