blob: efc0afecf5abdbcea486971e69bc78a871c2e88f [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00002import unittest
3
Nick Coghland6245172013-05-07 00:03:00 +10004from test.bytecode_helper import BytecodeTestCase
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00005
Nick Coghland6245172013-05-07 00:03:00 +10006class TestTranforms(BytecodeTestCase):
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00007
8 def test_unot(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +00009 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE'
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000010 def unot(x):
11 if not x == 2:
12 del x
Nick Coghland6245172013-05-07 00:03:00 +100013 self.assertNotInBytecode(unot, 'UNARY_NOT')
14 self.assertNotInBytecode(unot, 'POP_JUMP_IF_FALSE')
15 self.assertInBytecode(unot, 'POP_JUMP_IF_TRUE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000016
17 def test_elim_inversion_of_is_or_in(self):
Nick Coghland6245172013-05-07 00:03:00 +100018 for line, cmp_op in (
19 ('not a is b', 'is not',),
20 ('not a in b', 'not in',),
21 ('not a is not b', 'is',),
22 ('not a not in b', 'in',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000023 ):
Nick Coghland6245172013-05-07 00:03:00 +100024 code = compile(line, '', 'single')
25 self.assertInBytecode(code, 'COMPARE_OP', cmp_op)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000026
Guido van Rossumcd16bf62007-06-13 18:07:49 +000027 def test_global_as_constant(self):
28 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
Victor Stinner51d8c522016-02-08 17:57:02 +010029 def f():
30 x = None
31 x = None
Tim Peters66cb0182004-08-26 05:23:19 +000032 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010033 def g():
34 x = True
Guido van Rossumcd16bf62007-06-13 18:07:49 +000035 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010036 def h():
37 x = False
Guido van Rossumcd16bf62007-06-13 18:07:49 +000038 return x
Victor Stinner51d8c522016-02-08 17:57:02 +010039
Nick Coghland6245172013-05-07 00:03:00 +100040 for func, elem in ((f, None), (g, True), (h, False)):
41 self.assertNotInBytecode(func, 'LOAD_GLOBAL')
42 self.assertInBytecode(func, 'LOAD_CONST', elem)
Victor Stinner51d8c522016-02-08 17:57:02 +010043
Guido van Rossumd8faa362007-04-27 19:54:29 +000044 def f():
45 'Adding a docstring made this test fail in Py2.5.0'
46 return None
Victor Stinner51d8c522016-02-08 17:57:02 +010047
Nick Coghland6245172013-05-07 00:03:00 +100048 self.assertNotInBytecode(f, 'LOAD_GLOBAL')
49 self.assertInBytecode(f, 'LOAD_CONST', None)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000050
51 def test_while_one(self):
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000052 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000053 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000054 while 1:
55 pass
56 return list
Jeffrey Yasskin9de7ec72009-02-25 02:25:04 +000057 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
Nick Coghland6245172013-05-07 00:03:00 +100058 self.assertNotInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000059 for elem in ('JUMP_ABSOLUTE',):
Nick Coghland6245172013-05-07 00:03:00 +100060 self.assertInBytecode(f, elem)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000061
62 def test_pack_unpack(self):
63 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000064 ('a, = a,', 'LOAD_CONST',),
65 ('a, b = a, b', 'ROT_TWO',),
66 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000067 ):
Nick Coghland6245172013-05-07 00:03:00 +100068 code = compile(line,'','single')
69 self.assertInBytecode(code, elem)
70 self.assertNotInBytecode(code, 'BUILD_TUPLE')
71 self.assertNotInBytecode(code, 'UNPACK_TUPLE')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000072
Raymond Hettinger2c31a052004-09-22 18:44:21 +000073 def test_folding_of_tuples_of_constants(self):
74 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +100075 ('a = 1,2,3', (1, 2, 3)),
76 ('("a","b","c")', ('a', 'b', 'c')),
77 ('a,b,c = 1,2,3', (1, 2, 3)),
78 ('(None, 1, None)', (None, 1, None)),
79 ('((1, 2), 3, 4)', ((1, 2), 3, 4)),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000080 ):
Nick Coghland6245172013-05-07 00:03:00 +100081 code = compile(line,'','single')
82 self.assertInBytecode(code, 'LOAD_CONST', elem)
83 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Raymond Hettinger2c31a052004-09-22 18:44:21 +000084
Antoine Pitrou17b880a2011-03-11 17:27:02 +010085 # Long tuples should be folded too.
Nick Coghland6245172013-05-07 00:03:00 +100086 code = compile(repr(tuple(range(10000))),'','single')
87 self.assertNotInBytecode(code, 'BUILD_TUPLE')
Antoine Pitrou17b880a2011-03-11 17:27:02 +010088 # One LOAD_CONST for the tuple, one for the None return value
Nick Coghland6245172013-05-07 00:03:00 +100089 load_consts = [instr for instr in dis.get_instructions(code)
90 if instr.opname == 'LOAD_CONST']
91 self.assertEqual(len(load_consts), 2)
Antoine Pitrou17b880a2011-03-11 17:27:02 +010092
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
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000110 def test_folding_of_lists_of_constants(self):
111 for line, elem in (
112 # in/not in constants with BUILD_LIST should be folded to a tuple:
Nick Coghland6245172013-05-07 00:03:00 +1000113 ('a in [1,2,3]', (1, 2, 3)),
114 ('a not in ["a","b","c"]', ('a', 'b', 'c')),
115 ('a in [None, 1, None]', (None, 1, None)),
116 ('a not in [(1, 2), 3, 4]', ((1, 2), 3, 4)),
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000117 ):
Nick Coghland6245172013-05-07 00:03:00 +1000118 code = compile(line, '', 'single')
119 self.assertInBytecode(code, 'LOAD_CONST', elem)
120 self.assertNotInBytecode(code, 'BUILD_LIST')
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000121
122 def test_folding_of_sets_of_constants(self):
123 for line, elem in (
124 # in/not in constants with BUILD_SET should be folded to a frozenset:
125 ('a in {1,2,3}', frozenset({1, 2, 3})),
126 ('a not in {"a","b","c"}', frozenset({'a', 'c', 'b'})),
127 ('a in {None, 1, None}', frozenset({1, None})),
128 ('a not in {(1, 2), 3, 4}', frozenset({(1, 2), 3, 4})),
129 ('a in {1, 2, 3, 3, 2, 1}', frozenset({1, 2, 3})),
130 ):
Nick Coghland6245172013-05-07 00:03:00 +1000131 code = compile(line, '', 'single')
132 self.assertNotInBytecode(code, 'BUILD_SET')
133 self.assertInBytecode(code, 'LOAD_CONST', elem)
Antoine Pitroub7fbcd32010-01-16 18:37:38 +0000134
135 # Ensure that the resulting code actually works:
136 def f(a):
137 return a in {1, 2, 3}
138
139 def g(a):
140 return a not in {1, 2, 3}
141
142 self.assertTrue(f(3))
143 self.assertTrue(not f(4))
144
145 self.assertTrue(not g(3))
146 self.assertTrue(g(4))
147
148
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000149 def test_folding_of_binops_on_constants(self):
150 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000151 ('a = 2+3+4', 9), # chained fold
152 ('"@"*4', '@@@@'), # check string ops
153 ('a="abc" + "def"', 'abcdef'), # check string ops
154 ('a = 3**4', 81), # binary power
155 ('a = 3*4', 12), # binary multiply
156 ('a = 13//4', 3), # binary floor divide
157 ('a = 14%4', 2), # binary modulo
158 ('a = 2+3', 5), # binary add
159 ('a = 13-4', 9), # binary subtract
160 ('a = (12,13)[1]', 13), # binary subscr
161 ('a = 13 << 2', 52), # binary lshift
162 ('a = 13 >> 2', 3), # binary rshift
163 ('a = 13 & 7', 5), # binary and
164 ('a = 13 ^ 7', 10), # binary xor
165 ('a = 13 | 7', 15), # binary or
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000166 ):
Nick Coghland6245172013-05-07 00:03:00 +1000167 code = compile(line, '', 'single')
168 self.assertInBytecode(code, 'LOAD_CONST', elem)
169 for instr in dis.get_instructions(code):
170 self.assertFalse(instr.opname.startswith('BINARY_'))
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000171
172 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000173 code = compile('a=2+"b"', '', 'single')
174 self.assertInBytecode(code, 'LOAD_CONST', 2)
175 self.assertInBytecode(code, 'LOAD_CONST', 'b')
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000176
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000177 # Verify that large sequences do not result from folding
Nick Coghland6245172013-05-07 00:03:00 +1000178 code = compile('a="x"*1000', '', 'single')
179 self.assertInBytecode(code, 'LOAD_CONST', 1000)
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000180
Ezio Melotti2df6a932011-04-15 16:38:34 +0300181 def test_binary_subscr_on_unicode(self):
182 # valid code get optimized
Nick Coghland6245172013-05-07 00:03:00 +1000183 code = compile('"foo"[0]', '', 'single')
184 self.assertInBytecode(code, 'LOAD_CONST', 'f')
185 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
186 code = compile('"\u0061\uffff"[1]', '', 'single')
187 self.assertInBytecode(code, 'LOAD_CONST', '\uffff')
188 self.assertNotInBytecode(code,'BINARY_SUBSCR')
189
190 # With PEP 393, non-BMP char get optimized
191 code = compile('"\U00012345"[0]', '', 'single')
192 self.assertInBytecode(code, 'LOAD_CONST', '\U00012345')
193 self.assertNotInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300194
195 # invalid code doesn't get optimized
196 # out of range
Nick Coghland6245172013-05-07 00:03:00 +1000197 code = compile('"fuu"[10]', '', 'single')
198 self.assertInBytecode(code, 'BINARY_SUBSCR')
Ezio Melotti2df6a932011-04-15 16:38:34 +0300199
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000200 def test_folding_of_unaryops_on_constants(self):
201 for line, elem in (
Nick Coghland6245172013-05-07 00:03:00 +1000202 ('-0.5', -0.5), # unary negative
203 ('-0.0', -0.0), # -0.0
204 ('-(1.0-1.0)', -0.0), # -0.0 after folding
205 ('-0', 0), # -0
206 ('~-2', 1), # unary invert
207 ('+1', 1), # unary positive
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000208 ):
Nick Coghland6245172013-05-07 00:03:00 +1000209 code = compile(line, '', 'single')
210 self.assertInBytecode(code, 'LOAD_CONST', elem)
211 for instr in dis.get_instructions(code):
212 self.assertFalse(instr.opname.startswith('UNARY_'))
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000213
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000214 # Check that -0.0 works after marshaling
215 def negzero():
216 return -(1.0-1.0)
217
Nick Coghland6245172013-05-07 00:03:00 +1000218 for instr in dis.get_instructions(code):
219 self.assertFalse(instr.opname.startswith('UNARY_'))
Mark Dickinson7c9e8032011-03-23 17:59:37 +0000220
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000221 # Verify that unfoldables are skipped
Nick Coghland6245172013-05-07 00:03:00 +1000222 for line, elem, opname in (
223 ('-"abc"', 'abc', 'UNARY_NEGATIVE'),
224 ('~"abc"', 'abc', 'UNARY_INVERT'),
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000225 ):
Nick Coghland6245172013-05-07 00:03:00 +1000226 code = compile(line, '', 'single')
227 self.assertInBytecode(code, 'LOAD_CONST', elem)
228 self.assertInBytecode(code, opname)
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000229
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000230 def test_elim_extra_return(self):
231 # RETURN LOAD_CONST None RETURN --> RETURN
232 def f(x):
233 return x
Nick Coghland6245172013-05-07 00:03:00 +1000234 self.assertNotInBytecode(f, 'LOAD_CONST', None)
235 returns = [instr for instr in dis.get_instructions(f)
236 if instr.opname == 'RETURN_VALUE']
237 self.assertEqual(len(returns), 1)
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000238
Thomas Wouters89f507f2006-12-13 04:49:30 +0000239 def test_elim_jump_to_return(self):
240 # JUMP_FORWARD to RETURN --> RETURN
241 def f(cond, true_value, false_value):
242 return true_value if cond else false_value
Nick Coghland6245172013-05-07 00:03:00 +1000243 self.assertNotInBytecode(f, 'JUMP_FORWARD')
244 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
245 returns = [instr for instr in dis.get_instructions(f)
246 if instr.opname == 'RETURN_VALUE']
247 self.assertEqual(len(returns), 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000248
249 def test_elim_jump_after_return1(self):
250 # Eliminate dead code: jumps immediately after returns can't be reached
251 def f(cond1, cond2):
252 if cond1: return 1
253 if cond2: return 2
254 while 1:
255 return 3
256 while 1:
257 if cond1: return 4
258 return 5
259 return 6
Nick Coghland6245172013-05-07 00:03:00 +1000260 self.assertNotInBytecode(f, 'JUMP_FORWARD')
261 self.assertNotInBytecode(f, 'JUMP_ABSOLUTE')
262 returns = [instr for instr in dis.get_instructions(f)
263 if instr.opname == 'RETURN_VALUE']
264 self.assertEqual(len(returns), 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000265
266 def test_elim_jump_after_return2(self):
267 # Eliminate dead code: jumps immediately after returns can't be reached
268 def f(cond1, cond2):
269 while 1:
270 if cond1: return 4
Nick Coghland6245172013-05-07 00:03:00 +1000271 self.assertNotInBytecode(f, 'JUMP_FORWARD')
Thomas Wouters89f507f2006-12-13 04:49:30 +0000272 # There should be one jump for the while loop.
Nick Coghland6245172013-05-07 00:03:00 +1000273 returns = [instr for instr in dis.get_instructions(f)
274 if instr.opname == 'JUMP_ABSOLUTE']
275 self.assertEqual(len(returns), 1)
276 returns = [instr for instr in dis.get_instructions(f)
277 if instr.opname == 'RETURN_VALUE']
278 self.assertEqual(len(returns), 2)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000279
Guido van Rossum0240b922007-02-26 21:23:50 +0000280 def test_make_function_doesnt_bail(self):
281 def f():
Guido van Rossumd8faa362007-04-27 19:54:29 +0000282 def g()->1+1:
Guido van Rossum0240b922007-02-26 21:23:50 +0000283 pass
284 return g
Nick Coghland6245172013-05-07 00:03:00 +1000285 self.assertNotInBytecode(f, 'BINARY_ADD')
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000286
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100287 def test_constant_folding(self):
288 # Issue #11244: aggressive constant folding.
289 exprs = [
Nick Coghland6245172013-05-07 00:03:00 +1000290 '3 * -5',
291 '-3 * 5',
292 '2 * (3 * 4)',
293 '(2 * 3) * 4',
294 '(-1, 2, 3)',
295 '(1, -2, 3)',
296 '(1, 2, -3)',
297 '(1, 2, -3) * 6',
298 'lambda x: x in {(3 * -5) + (-1 - 6), (1, -2, 3) * 2, None}',
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100299 ]
300 for e in exprs:
Nick Coghland6245172013-05-07 00:03:00 +1000301 code = compile(e, '', 'single')
302 for instr in dis.get_instructions(code):
303 self.assertFalse(instr.opname.startswith('UNARY_'))
304 self.assertFalse(instr.opname.startswith('BINARY_'))
305 self.assertFalse(instr.opname.startswith('BUILD_'))
306
Antoine Pitrou17b880a2011-03-11 17:27:02 +0100307
Raymond Hettinger0661e912011-03-15 15:03:36 -0700308class TestBuglets(unittest.TestCase):
309
Raymond Hettinger5bd75b82011-03-15 15:07:38 -0700310 def test_bug_11510(self):
311 # folded constant set optimization was commingled with the tuple
312 # unpacking optimization which would fail if the set had duplicate
313 # elements so that the set length was unexpected
314 def f():
315 x, y = {1, 1}
316 return x, y
317 with self.assertRaises(ValueError):
318 f()
Raymond Hettinger0661e912011-03-15 15:03:36 -0700319
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000320
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000321if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500322 unittest.main()