blob: 41e5091fabd18d4c81fe362947ac09d301c55073 [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
Antoine Pitroub7fbcd32010-01-16 18:37:38 +00002import re
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00003import sys
Guido van Rossum34d19282007-08-09 01:03:29 +00004from io import StringIO
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00005import unittest
Mark Dickinson7c9e8032011-03-23 17:59:37 +00006from math import copysign
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00007
Nick Coghland6245172013-05-07 00:03:00 +10008from test.bytecode_helper import BytecodeTestCase
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00009
Nick Coghland6245172013-05-07 00:03:00 +100010class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000011
12 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000013 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000014 def unot(x):
15 if not x == 2:
16 del x
Nick Coghland6245172013-05-07 00:03:00 +100017 self.assertNotInBytecode(unot, 'UNARY_NOT')
18 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
19 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000020
21 def test_elim_inversion_of_is_or_in(self):
Nick Coghland6245172013-05-07 00:03:00 +100022 for line, cmp_op in (
23 ('not a is b', 'is not',),
24 ('not a in b', 'not in',),
25 ('not a is not b', 'is',),
26 ('not a not in b', 'in',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000027 ):
Nick Coghland6245172013-05-07 00:03:00 +100028 code = compile(line, '', 'single')
29 self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000030
Guido van Rossumcd16bf62007-06-13 18:07:49 +000031 def test_global_as_constant(self):
32 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000033 def f(x):
Tim Peters66cb0182004-08-26 05:23:19 +000034 None
Guido van Rossumcd16bf62007-06-13 18:07:49 +000035 None
Tim Peters66cb0182004-08-26 05:23:19 +000036 return x
Guido van Rossumcd16bf62007-06-13 18:07:49 +000037 def g(x):
38 True
39 return x
40 def h(x):
41 False
42 return x
Nick Coghland6245172013-05-07 00:03:00 +100043 for func, elem in ((f, None), (g, True), (h, False)):
44 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
45 self.assertInBytecode(func, 'LOAD_CONST', elem)
Guido van Rossumd8faa362007-04-27 19:54:29 +000046 def f():
47 'Adding a docstring made this test fail in Py2.5.0'
48 return None
Nick Coghland6245172013-05-07 00:03:00 +100049 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
50 self.assertInBytecode(f, 'LOAD_CONST', None)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000051
52 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000053 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000054 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000055 while 1:
56 pass
57 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000058 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +100059 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000060 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +100061 self.assertInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000062
63 def test_pack_unpack(self):
64 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000065 ('a, = a,', 'LOAD_CONST',),
66 ('a, b = a, b', 'ROT_TWO',),
67 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000068 ):
Nick Coghland6245172013-05-07 00:03:00 +100069 code = compile(line,'','single')
70 self.assertInBytecode(code, elem)
71 self.assertNotInBytecode(code, 'BUILD_TUPLE')
72 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000073
Raymond Hettinger2c31a052004-09-22 18:44:21 +000074 def test_folding_of_tuples_of_constants(self):
75 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +100076 ('a = 1,2,3', (1, 2, 3)),
77 ('("a","b","c")', ('a', 'b', 'c')),
78 ('a,b,c = 1,2,3', (1, 2, 3)),
79 ('(None, 1, None)', (None, 1, None)),
80 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000081 ):
Nick Coghland6245172013-05-07 00:03:00 +100082 code = compile(line,'','single')
83 self.assertInBytecode(code, 'LOAD_CONST', elem)
84 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Raymond Hettinger2c31a052004-09-22 18:44:21 +000085
Antoine Pitrou17b880a2011-03-11 17:27:02 +010086 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +100087 code = compile(repr(tuple(range(10000))),'','single')
88 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +010089 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +100090 load_consts = [instr for instr in dis.get_instructions(code)
91 if instr.opname == 'LOAD_CONST']
92 self.assertEqual(len(load_consts), 2)
Antoine Pitrou17b880a2011-03-11 17:27:02 +010093
Raymond Hettinger23109ef2004-10-26 08:59:14 +000094 # Bug 1053819: Tuple of constants misidentified when presented with:
95 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
96 # The following would segfault upon compilation
97 def crater():
98 (~[
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 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
109 ],)
110
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000111 def test_folding_of_lists_of_constants(self):
112 for line, elem in (
113 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000114 ('a in [1,2,3]', (1, 2, 3)),
115 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
116 ('a in [None, 1, None]', (None, 1, None)),
117 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000118 ):
Nick Coghland6245172013-05-07 00:03:00 +1000119 code = compile(line, '', 'single')
120 self.assertInBytecode(code, 'LOAD_CONST', elem)
121 self.assertNotInBytecode(code, 'BUILD_LIST')
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000122
123 def test_folding_of_sets_of_constants(self):
124 for line, elem in (
125 # in/not in constants with BUILD_SET should be folded to a frozenset:
126 ('a in {1,2,3}', frozenset({1, 2, 3})),
127 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
128 ('a in {None, 1, None}', frozenset({1, None})),
129 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
130 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
131 ):
Nick Coghland6245172013-05-07 00:03:00 +1000132 code = compile(line, '', 'single')
133 self.assertNotInBytecode(code, 'BUILD_SET')
134 self.assertInBytecode(code, 'LOAD_CONST', elem)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000135
136 # Ensure that the resulting code actually works:
137 def f(a):
138 return a in {1, 2, 3}
139
140 def g(a):
141 return a not in {1, 2, 3}
142
143 self.assertTrue(f(3))
144 self.assertTrue(not f(4))
145
146 self.assertTrue(not g(3))
147 self.assertTrue(g(4))
148
149
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000150 def test_folding_of_binops_on_constants(self):
151 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000152 ('a = 2+3+4', 9), # chained fold
153 ('"@"*4', '@@@@'), # check string ops
154 ('a="abc" + "def"', 'abcdef'), # check string ops
155 ('a = 3**4', 81), # binary power
156 ('a = 3*4', 12), # binary multiply
157 ('a = 13//4', 3), # binary floor divide
158 ('a = 14%4', 2), # binary modulo
159 ('a = 2+3', 5), # binary add
160 ('a = 13-4', 9), # binary subtract
161 ('a = (12,13)[1]', 13), # binary subscr
162 ('a = 13 << 2', 52), # binary lshift
163 ('a = 13 >> 2', 3), # binary rshift
164 ('a = 13 & 7', 5), # binary and
165 ('a = 13 ^ 7', 10), # binary xor
166 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000167 ):
Nick Coghland6245172013-05-07 00:03:00 +1000168 code = compile(line, '', 'single')
169 self.assertInBytecode(code, 'LOAD_CONST', elem)
170 for instr in dis.get_instructions(code):
171 self.assertFalse(instr.opname.startswith('BINARY_'))
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000172
173 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000174 code = compile('a=2+"b"', '', 'single')
175 self.assertInBytecode(code, 'LOAD_CONST', 2)
176 self.assertInBytecode(code, 'LOAD_CONST', 'b')
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000177
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000178 # Verify that large sequences do not result from folding
Nick Coghland6245172013-05-07 00:03:00 +1000179 code = compile('a="x"*1000', '', 'single')
180 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000181
Ezio Melotti2df6a932011-04-15 16:38:34 +0300182 def test_binary_subscr_on_unicode(self):
183 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000184 code = compile('"foo"[0]', '', 'single')
185 self.assertInBytecode(code, 'LOAD_CONST', 'f')
186 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
187 code = compile('"\u0061\uffff"[1]', '', 'single')
188 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
189 self.assertNotInBytecode(code,'BINARY_SUBSCR')
190
191 # With PEP 393, non-BMP char get optimized
192 code = compile('"\U00012345"[0]', '', 'single')
193 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
194 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300195
196 # invalid code doesn't get optimized
197 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000198 code = compile('"fuu"[10]', '', 'single')
199 self.assertInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300200
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000201 def test_folding_of_unaryops_on_constants(self):
202 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000203 ('-0.5', -0.5), # unary negative
204 ('-0.0', -0.0), # -0.0
205 ('-(1.0-1.0)', -0.0), # -0.0 after folding
206 ('-0', 0), # -0
207 ('~-2', 1), # unary invert
208 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000209 ):
Nick Coghland6245172013-05-07 00:03:00 +1000210 code = compile(line, '', 'single')
211 self.assertInBytecode(code, 'LOAD_CONST', elem)
212 for instr in dis.get_instructions(code):
213 self.assertFalse(instr.opname.startswith('UNARY_'))
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000214
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000215 # Check that -0.0 works after marshaling
216 def negzero():
217 return -(1.0-1.0)
218
Nick Coghland6245172013-05-07 00:03:00 +1000219 for instr in dis.get_instructions(code):
220 self.assertFalse(instr.opname.startswith('UNARY_'))
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000221
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000222 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000223 for line, elem, opname in (
224 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
225 ('~"abc"', 'abc', 'UNARY_INVERT'),
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000226 ):
Nick Coghland6245172013-05-07 00:03:00 +1000227 code = compile(line, '', 'single')
228 self.assertInBytecode(code, 'LOAD_CONST', elem)
229 self.assertInBytecode(code, opname)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000230
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000231 def test_elim_extra_return(self):
232 # RETURN LOAD_CONST None RETURN --> RETURN
233 def f(x):
234 return x
Nick Coghland6245172013-05-07 00:03:00 +1000235 self.assertNotInBytecode(f, 'LOAD_CONST', None)
236 returns = [instr for instr in dis.get_instructions(f)
237 if instr.opname == 'RETURN_VALUE']
238 self.assertEqual(len(returns), 1)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000239
Thomas Wouters89f507f2006-12-13 04:49:30 +0000240 def test_elim_jump_to_return(self):
241 # JUMP_FORWARD to RETURN --> RETURN
242 def f(cond, true_value, false_value):
243 return true_value if cond else false_value
Nick Coghland6245172013-05-07 00:03:00 +1000244 self.assertNotInBytecode(f, 'JUMP_FORWARD')
245 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
246 returns = [instr for instr in dis.get_instructions(f)
247 if instr.opname == 'RETURN_VALUE']
248 self.assertEqual(len(returns), 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000249
250 def test_elim_jump_after_return1(self):
251 # Eliminate dead code: jumps immediately after returns can't be reached
252 def f(cond1, cond2):
253 if cond1: return 1
254 if cond2: return 2
255 while 1:
256 return 3
257 while 1:
258 if cond1: return 4
259 return 5
260 return 6
Nick Coghland6245172013-05-07 00:03:00 +1000261 self.assertNotInBytecode(f, 'JUMP_FORWARD')
262 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
263 returns = [instr for instr in dis.get_instructions(f)
264 if instr.opname == 'RETURN_VALUE']
265 self.assertEqual(len(returns), 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000266
267 def test_elim_jump_after_return2(self):
268 # Eliminate dead code: jumps immediately after returns can't be reached
269 def f(cond1, cond2):
270 while 1:
271 if cond1: return 4
Nick Coghland6245172013-05-07 00:03:00 +1000272 self.assertNotInBytecode(f, 'JUMP_FORWARD')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000273 # There should be one jump for the while loop.
Nick Coghland6245172013-05-07 00:03:00 +1000274 returns = [instr for instr in dis.get_instructions(f)
275 if instr.opname == 'JUMP_ABSOLUTE']
276 self.assertEqual(len(returns), 1)
277 returns = [instr for instr in dis.get_instructions(f)
278 if instr.opname == 'RETURN_VALUE']
279 self.assertEqual(len(returns), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000280
Guido van Rossum0240b922007-02-26 21:23:50 +0000281 def test_make_function_doesnt_bail(self):
282 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000283 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000284 pass
285 return g
Nick Coghland6245172013-05-07 00:03:00 +1000286 self.assertNotInBytecode(f, 'BINARY_ADD')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000287
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100288 def test_constant_folding(self):
289 # Issue #11244: aggressive constant folding.
290 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000291 '3 * -5',
292 '-3 * 5',
293 '2 * (3 * 4)',
294 '(2 * 3) * 4',
295 '(-1, 2, 3)',
296 '(1, -2, 3)',
297 '(1, 2, -3)',
298 '(1, 2, -3) * 6',
299 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100300 ]
301 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000302 code = compile(e, '', 'single')
303 for instr in dis.get_instructions(code):
304 self.assertFalse(instr.opname.startswith('UNARY_'))
305 self.assertFalse(instr.opname.startswith('BINARY_'))
306 self.assertFalse(instr.opname.startswith('BUILD_'))
307
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100308
Raymond Hettinger0661e912011-03-15 15:03:36 -0700309class TestBuglets(unittest.TestCase):
310
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700311 def test_bug_11510(self):
312 # folded constant set optimization was commingled with the tuple
313 # unpacking optimization which would fail if the set had duplicate
314 # elements so that the set length was unexpected
315 def f():
316 x, y = {1, 1}
317 return x, y
318 with self.assertRaises(ValueError):
319 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700320
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000321
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000322if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500323 unittest.main()