blob: 6638a5a4c4476f906b02ec115c53a564455ade5a [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
2import sys
3from cStringIO import StringIO
4import unittest
5
6def disassemble(func):
7 f = StringIO()
8 tmp = sys.stdout
9 sys.stdout = f
10 dis.dis(func)
11 sys.stdout = tmp
12 result = f.getvalue()
13 f.close()
14 return result
15
16def dis_single(line):
17 return disassemble(compile(line, '', 'single'))
18
19class TestTranforms(unittest.TestCase):
20
21 def test_unot(self):
Jeffrey Yasskin68d68522009-02-28 19:03:21 +000022 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000023 def unot(x):
24 if not x == 2:
25 del x
26 asm = disassemble(unot)
Jeffrey Yasskin68d68522009-02-28 19:03:21 +000027 for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000028 self.assert_(elem not in asm)
Jeffrey Yasskin68d68522009-02-28 19:03:21 +000029 self.assert_('POP_JUMP_IF_TRUE' in asm)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000030
31 def test_elim_inversion_of_is_or_in(self):
32 for line, elem in (
33 ('not a is b', '(is not)',),
34 ('not a in b', '(not in)',),
35 ('not a is not b', '(is)',),
36 ('not a not in b', '(in)',),
37 ):
38 asm = dis_single(line)
39 self.assert_(elem in asm)
40
41 def test_none_as_constant(self):
42 # LOAD_GLOBAL None --> LOAD_CONST None
43 def f(x):
Tim Peters66cb0182004-08-26 05:23:19 +000044 None
45 return x
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000046 asm = disassemble(f)
47 for elem in ('LOAD_GLOBAL',):
48 self.assert_(elem not in asm)
49 for elem in ('LOAD_CONST', '(None)'):
50 self.assert_(elem in asm)
Raymond Hettinger20e11992007-03-02 19:20:46 +000051 def f():
52 'Adding a docstring made this test fail in Py2.5.0'
53 return None
54 self.assert_('LOAD_CONST' in disassemble(f))
55 self.assert_('LOAD_GLOBAL' not in disassemble(f))
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000056
57 def test_while_one(self):
Jeffrey Yasskin68d68522009-02-28 19:03:21 +000058 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000059 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000060 while 1:
61 pass
62 return list
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000063 asm = disassemble(f)
Jeffrey Yasskin68d68522009-02-28 19:03:21 +000064 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000065 self.assert_(elem not in asm)
66 for elem in ('JUMP_ABSOLUTE',):
67 self.assert_(elem in asm)
68
69 def test_pack_unpack(self):
70 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000071 ('a, = a,', 'LOAD_CONST',),
72 ('a, b = a, b', 'ROT_TWO',),
73 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000074 ):
75 asm = dis_single(line)
76 self.assert_(elem in asm)
77 self.assert_('BUILD_TUPLE' not in asm)
78 self.assert_('UNPACK_TUPLE' not in asm)
79
Raymond Hettinger2c31a052004-09-22 18:44:21 +000080 def test_folding_of_tuples_of_constants(self):
81 for line, elem in (
Raymond Hettinger5dec0962004-11-02 04:20:10 +000082 ('a = 1,2,3', '((1, 2, 3))'),
83 ('("a","b","c")', "(('a', 'b', 'c'))"),
84 ('a,b,c = 1,2,3', '((1, 2, 3))'),
85 ('(None, 1, None)', '((None, 1, None))'),
86 ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000087 ):
88 asm = dis_single(line)
89 self.assert_(elem in asm)
90 self.assert_('BUILD_TUPLE' not in asm)
91
Raymond Hettinger23109ef2004-10-26 08:59:14 +000092 # Bug 1053819: Tuple of constants misidentified when presented with:
93 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
94 # The following would segfault upon compilation
95 def crater():
96 (~[
97 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
98 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
99 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
101 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
104 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
105 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
106 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
107 ],)
108
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000109 def test_folding_of_binops_on_constants(self):
110 for line, elem in (
111 ('a = 2+3+4', '(9)'), # chained fold
112 ('"@"*4', "('@@@@')"), # check string ops
113 ('a="abc" + "def"', "('abcdef')"), # check string ops
114 ('a = 3**4', '(81)'), # binary power
115 ('a = 3*4', '(12)'), # binary multiply
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000116 ('a = 13//4', '(3)'), # binary floor divide
117 ('a = 14%4', '(2)'), # binary modulo
118 ('a = 2+3', '(5)'), # binary add
119 ('a = 13-4', '(9)'), # binary subtract
120 ('a = (12,13)[1]', '(13)'), # binary subscr
121 ('a = 13 << 2', '(52)'), # binary lshift
122 ('a = 13 >> 2', '(3)'), # binary rshift
123 ('a = 13 & 7', '(5)'), # binary and
124 ('a = 13 ^ 7', '(10)'), # binary xor
125 ('a = 13 | 7', '(15)'), # binary or
126 ):
127 asm = dis_single(line)
128 self.assert_(elem in asm, asm)
129 self.assert_('BINARY_' not in asm)
130
131 # Verify that unfoldables are skipped
132 asm = dis_single('a=2+"b"')
133 self.assert_('(2)' in asm)
134 self.assert_("('b')" in asm)
135
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000136 # Verify that large sequences do not result from folding
137 asm = dis_single('a="x"*1000')
138 self.assert_('(1000)' in asm)
139
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000140 def test_folding_of_unaryops_on_constants(self):
141 for line, elem in (
142 ('`1`', "('1')"), # unary convert
143 ('-0.5', '(-0.5)'), # unary negative
144 ('~-2', '(1)'), # unary invert
145 ):
146 asm = dis_single(line)
147 self.assert_(elem in asm, asm)
148 self.assert_('UNARY_' not in asm)
149
150 # Verify that unfoldables are skipped
151 for line, elem in (
152 ('-"abc"', "('abc')"), # unary negative
153 ('~"abc"', "('abc')"), # unary invert
154 ):
155 asm = dis_single(line)
156 self.assert_(elem in asm, asm)
157 self.assert_('UNARY_' in asm)
158
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000159 def test_elim_extra_return(self):
160 # RETURN LOAD_CONST None RETURN --> RETURN
161 def f(x):
162 return x
163 asm = disassemble(f)
164 self.assert_('LOAD_CONST' not in asm)
165 self.assert_('(None)' not in asm)
166 self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
167
Neal Norwitzcbeb6872006-10-14 21:33:38 +0000168 def test_elim_jump_to_return(self):
169 # JUMP_FORWARD to RETURN --> RETURN
170 def f(cond, true_value, false_value):
171 return true_value if cond else false_value
172 asm = disassemble(f)
173 self.assert_('JUMP_FORWARD' not in asm)
174 self.assert_('JUMP_ABSOLUTE' not in asm)
175 self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
176
177 def test_elim_jump_after_return1(self):
178 # Eliminate dead code: jumps immediately after returns can't be reached
179 def f(cond1, cond2):
180 if cond1: return 1
181 if cond2: return 2
182 while 1:
183 return 3
184 while 1:
185 if cond1: return 4
186 return 5
187 return 6
188 asm = disassemble(f)
189 self.assert_('JUMP_FORWARD' not in asm)
190 self.assert_('JUMP_ABSOLUTE' not in asm)
191 self.assertEqual(asm.split().count('RETURN_VALUE'), 6)
192
193 def test_elim_jump_after_return2(self):
194 # Eliminate dead code: jumps immediately after returns can't be reached
195 def f(cond1, cond2):
196 while 1:
197 if cond1: return 4
198 asm = disassemble(f)
199 self.assert_('JUMP_FORWARD' not in asm)
200 # There should be one jump for the while loop.
201 self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1)
202 self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000203
204
205def test_main(verbose=None):
206 import sys
207 from test import test_support
208 test_classes = (TestTranforms,)
209 test_support.run_unittest(*test_classes)
210
211 # verify reference counting
212 if verbose and hasattr(sys, "gettotalrefcount"):
213 import gc
214 counts = [None] * 5
215 for i in xrange(len(counts)):
216 test_support.run_unittest(*test_classes)
217 gc.collect()
218 counts[i] = sys.gettotalrefcount()
219 print counts
220
221if __name__ == "__main__":
222 test_main(verbose=True)