blob: 1611e39479dcdb94618032796b20b2cbe3df0f1e [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):
22 # UNARY_NOT JUMP_IF_FALSE POP_TOP --> JUMP_IF_TRUE POP_TOP'
23 def unot(x):
24 if not x == 2:
25 del x
26 asm = disassemble(unot)
27 for elem in ('UNARY_NOT', 'JUMP_IF_FALSE'):
28 self.assert_(elem not in asm)
29 for elem in ('JUMP_IF_TRUE', 'POP_TOP'):
30 self.assert_(elem in asm)
31
32 def test_elim_inversion_of_is_or_in(self):
33 for line, elem in (
34 ('not a is b', '(is not)',),
35 ('not a in b', '(not in)',),
36 ('not a is not b', '(is)',),
37 ('not a not in b', '(in)',),
38 ):
39 asm = dis_single(line)
40 self.assert_(elem in asm)
41
42 def test_none_as_constant(self):
43 # LOAD_GLOBAL None --> LOAD_CONST None
44 def f(x):
Tim Peters66cb0182004-08-26 05:23:19 +000045 None
46 return x
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000047 asm = disassemble(f)
48 for elem in ('LOAD_GLOBAL',):
49 self.assert_(elem not in asm)
50 for elem in ('LOAD_CONST', '(None)'):
51 self.assert_(elem in asm)
Guido van Rossumd8faa362007-04-27 19:54:29 +000052 def f():
53 'Adding a docstring made this test fail in Py2.5.0'
54 return None
55 self.assert_('LOAD_CONST' in disassemble(f))
56 self.assert_('LOAD_GLOBAL' not in disassemble(f))
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000057
58 def test_while_one(self):
59 # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP
60 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000061 while 1:
62 pass
63 return list
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000064 asm = disassemble(f)
65 for elem in ('LOAD_CONST', 'JUMP_IF_FALSE'):
66 self.assert_(elem not in asm)
67 for elem in ('JUMP_ABSOLUTE',):
68 self.assert_(elem in asm)
69
70 def test_pack_unpack(self):
71 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000072 ('a, = a,', 'LOAD_CONST',),
73 ('a, b = a, b', 'ROT_TWO',),
74 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000075 ):
76 asm = dis_single(line)
77 self.assert_(elem in asm)
78 self.assert_('BUILD_TUPLE' not in asm)
79 self.assert_('UNPACK_TUPLE' not in asm)
80
Raymond Hettinger2c31a052004-09-22 18:44:21 +000081 def test_folding_of_tuples_of_constants(self):
82 for line, elem in (
Raymond Hettinger5dec0962004-11-02 04:20:10 +000083 ('a = 1,2,3', '((1, 2, 3))'),
84 ('("a","b","c")', "(('a', 'b', 'c'))"),
85 ('a,b,c = 1,2,3', '((1, 2, 3))'),
86 ('(None, 1, None)', '((None, 1, None))'),
87 ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000088 ):
89 asm = dis_single(line)
90 self.assert_(elem in asm)
91 self.assert_('BUILD_TUPLE' not in asm)
92
Raymond Hettinger23109ef2004-10-26 08:59:14 +000093 # Bug 1053819: Tuple of constants misidentified when presented with:
94 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
95 # The following would segfault upon compilation
96 def crater():
97 (~[
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 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
108 ],)
109
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000110 def test_folding_of_binops_on_constants(self):
111 for line, elem in (
112 ('a = 2+3+4', '(9)'), # chained fold
113 ('"@"*4', "('@@@@')"), # check string ops
114 ('a="abc" + "def"', "('abcdef')"), # check string ops
115 ('a = 3**4', '(81)'), # binary power
116 ('a = 3*4', '(12)'), # binary multiply
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000117 ('a = 13//4', '(3)'), # binary floor divide
118 ('a = 14%4', '(2)'), # binary modulo
119 ('a = 2+3', '(5)'), # binary add
120 ('a = 13-4', '(9)'), # binary subtract
121 ('a = (12,13)[1]', '(13)'), # binary subscr
122 ('a = 13 << 2', '(52)'), # binary lshift
123 ('a = 13 >> 2', '(3)'), # binary rshift
124 ('a = 13 & 7', '(5)'), # binary and
125 ('a = 13 ^ 7', '(10)'), # binary xor
126 ('a = 13 | 7', '(15)'), # binary or
127 ):
128 asm = dis_single(line)
129 self.assert_(elem in asm, asm)
130 self.assert_('BINARY_' not in asm)
131
132 # Verify that unfoldables are skipped
133 asm = dis_single('a=2+"b"')
134 self.assert_('(2)' in asm)
135 self.assert_("('b')" in asm)
136
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000137 # Verify that large sequences do not result from folding
138 asm = dis_single('a="x"*1000')
139 self.assert_('(1000)' in asm)
140
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000141 def test_folding_of_unaryops_on_constants(self):
142 for line, elem in (
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000143 ('-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
Thomas Wouters89f507f2006-12-13 04:49:30 +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)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000203
Guido van Rossum0240b922007-02-26 21:23:50 +0000204 def test_make_function_doesnt_bail(self):
205 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000206 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000207 pass
208 return g
209 asm = disassemble(f)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000210 self.assert_('BINARY_ADD' not in asm)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000211
212
213def test_main(verbose=None):
214 import sys
215 from test import test_support
216 test_classes = (TestTranforms,)
217 test_support.run_unittest(*test_classes)
218
219 # verify reference counting
220 if verbose and hasattr(sys, "gettotalrefcount"):
221 import gc
222 counts = [None] * 5
223 for i in xrange(len(counts)):
224 test_support.run_unittest(*test_classes)
225 gc.collect()
226 counts[i] = sys.gettotalrefcount()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000227 print(counts)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000228
229if __name__ == "__main__":
230 test_main(verbose=True)